문제 url:
설탕 배달
문제:
문제 자체는 간단해보인다. 실제로 풀어보니 헬이다 문제에 대해 간략히 알아보면,
3Kg 6개
로 가져가도 되지만, 적게 가져가기 위해서는5Kg 3개 3Kg 1개 총 4개
로 가져가야만 한다.그렇다면, N을 5로 나누었을 때, 나누어 떨어지지 않는다면 (ex. 15처럼 딱 떨어지지 않는다면)
3키로를 하나 카운트 한 다음, 5로 나누어지는지 확인하는 작업을 반복하면 구할 수 있을 것이다.
이 말이 무슨말인지를 설명하자면,
N이 9인 테스트 케이스를 보여준다면, 위의 그림처럼 나타낼 수 있다.
i는 그저 반복하고 있음을 알릴 뿐이다. 코드와는 상관 없다.
이런식으로, 봉지를 최소로 가져갈 수 있는 5kg으로 나눠을 때, 떨어지지 않는다면 3kg를 한개씩 담는다는 얘기이다.
N이 9인 경우는 아래와 같이 나눌 수 있다. 그렇다면 N이 18인 테스트 케이스는 어떨까?
다음과 같이 18은 5로 나누어 떨어지지 않기 때문에 3을 뺀 후 다음값과 비교했을 때, 15는 5로 나누어 떨어져서 값을 구할 수 있는 것을 볼 수 있다.
이번에는 반례로 7을 구해보자, 7은 5로도 3으로도 나누어 떨어지지 않는 값이다.
그림이 이해가 안된다면 코드를 같이 살펴보자
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int count = 0;
while(true) {
// N이 5로 다 나눠지거나 N이 0일 때 반복문에서 벗어남
if(N % 5 ==0) {
count+= N /5;
break;
// N이 0보다 작아지면 -1을 넣기.
// (즉, 크기가 알맞지 않다는 얘기)
} else if(N < 0) {
count = -1;
}
// 3키로 1개만큼 카운트 센 후, 총량에 3kg 빼기
N -= 3;
count++;
}
System.out.println(count);
}
}
위의 설명 그대로, N이 5로 나누어 떨어지지 않으면 3을 계속 빼면서 카운트를 세는 로직이며, N이 0보다 작아진다는 건 결국 5kg, 3kg로 소분하지 못한다는 의미기 때문에 조건에 맞게 -1을 출력한 것이다.
처음에 이렇게 생각하지는 않았다. 오히려 더 어렵게 생각했는데,
해당 값에서 나올 수 있는 모든 경우의 수를 조건을 달아서 계산하여 풀었다.
근데, 그럴 필요 없이 해당 조건이 전부 포함될 수 있는 코드를 짜면 간단한 것이다.
이걸 잘했으면 벌써 네이버 갔지
모든 조건에 만족하는 로직을 구현하며 이를 맞춰보면서 나중에 리팩토링을 했을 때 좀더 유연하고 간단하게 풀 수 있었던 것 같다. 아래는 이전 코드이다.
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int count = 0;
// 5로도 나눠지는데 해당 나머지가 3으로도 나눠질 때, 혹은 5로도 다 나눠지는 경우
if(N / 5 != 0 && N % 5 % 3 ==0) {
count += N / 5;
N %= 5;
count += N / 3;
// 5로는 나눠지는데, 나머지가 3으로 나눠지지 않는 경우.
} else if(N / 5 != 0 && N % 5 % 3 !=0) {
int min_count = 5000;
for(int i = 0; i <= N / 5; i++) {
// N의 값을 5의 배수로(5,10..)나누는데 나눈 후 나머지 값이 3으로 나누어 질 때,
// 21을 생각하면, 3 (7) / 5 (3) 3 (2)로, 5개가 가장 적게 나옴
// 그래서 min을 이용해 비교
if((N - (5 * i)) % 3 == 0) {
int temp_count = 0;
temp_count += i;
temp_count += (N - (5 * i)) / 3;
min_count = Math.min(min_count, temp_count);
}
}
if (min_count != 5000) {
count = min_count;
} else { // 반례가 7인 경우와 같이 둘 다 속하지 않을 떄 -1 출력
count = -1;
}
} else if(N / 5 == 0 && N % 5 % 3 ==0){ // ex) 3
count += N / 3;
} else { //ex) 4
count = -1;
}
System.out.println(count);
}
}
위의 코드와 비교하면 머리가 아플 것이다.
찾아보면 반례가 더 나올 수 있겠지만, 찾아볼 수 있는 조건은 아마 다 계산한 것 같다.
필자는 이러한 삽질은 좋아하지 않지만, 개발자는 이러한 삽질속에서 잔근육을 키운다는 얘기를 들어 최대한 삽질속에서 많은 것을 얻고자 노력하는 바이다.