ALGORITHM NOTE1

BOJ 2961 - 도영이가 만든 맛있는 음식

새로운 요리더라도 맛은 있어야지

#algorithm#boj#silver#brute-force#bitmask#backtracking
아카이브로 돌아가기

문제 링크

문제

도영이는 짜파구리 요리사로 명성을 날렸었다. 이번에는 이전에 없었던 새로운 요리에 도전을 해보려고 한다.

지금 도영이의 앞에는 재료가 N개 있다. 도영이는 각 재료의 신맛 S와 쓴맛 B를 알고 있다. 여러 재료를 이용해서 요리할 때, 그 음식의 신맛은 사용한 재료의 신맛의 곱이고, 쓴맛은 합이다.

시거나 쓴 음식을 좋아하는 사람은 많지 않다. 도영이는 재료를 적절히 섞어서 요리의 신맛과 쓴맛의 차이를 작게 만들려고 한다. 또, 물을 요리라고 할 수는 없기 때문에, 재료는 적어도 하나 사용해야 한다.

재료의 신맛과 쓴맛이 주어졌을 때, 신맛과 쓴맛의 차이가 가장 작은 요리를 만드는 프로그램을 작성하시오.

입력

첫째 줄에 재료의 개수 N(1 ≤ N ≤ 10)이 주어진다. 다음 N개 줄에는 그 재료의 신맛과 쓴맛이 공백으로 구분되어 주어진다. 모든 재료를 사용해서 요리를 만들었을 때, 그 요리의 신맛과 쓴맛은 모두 1,000,000,000보다 작은 양의 정수이다.

출력

첫째 줄에 신맛과 쓴맛의 차이가 가장 작은 요리의 차이를 출력한다.

풀이

각 재료를 넣을지 말지를 결정하는 모든 부분집합을 확인하면 된다. 선택된 재료들의 신맛은 곱으로 누적되고 쓴맛은 합으로 누적되므로, 공집합만 제외하고 |신맛 - 쓴맛|의 최솟값을 갱신하면 된다.

현재 코드는 재귀나 비트마스크로 재료 선택 여부를 나누며 탐색한다. 문제의 핵심은 신맛이 합이 아니라 곱이라는 점이라서, 상태를 갱신할 때 두 값을 각각 다른 방식으로 관리해야 한다.

코드

java
import java.io.*;
import java.util.*;
 
public class Main {
 
    static long ans = Long.MAX_VALUE;
    static int N;
    static int[][] arr;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
 
        N = Integer.parseInt(br.readLine());
        arr = new int[N][2];
 
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            arr[i][0] = Integer.parseInt(st.nextToken());
            arr[i][1] = Integer.parseInt(st.nextToken());
        }
 
        solve(0, 1, 0);
 
        System.out.println(ans);
    }
 
    static void solve(int cnt, long S, long B) {
        if (cnt == N) {
            if (S != 0 && B != 0)
                ans = Math.min(ans, Math.abs(B - S));
            return;
        }
 
        solve(cnt + 1, S, B);
        solve(cnt + 1, S * arr[cnt][0], B + arr[cnt][1]);
    }
}

복잡도

  • 시간 복잡도: 재료 부분집합을 모두 확인하므로 O(2N)O(2^N)이다.
  • 공간 복잡도: 재귀 스택과 재료 배열을 사용하므로 O(N)O(N)이다.

마무리

재료 수가 작으므로 모든 선택 조합을 직접 확인할 수 있다. 신맛은 곱, 쓴맛은 합으로 누적한다는 차이만 잘 지키면 최솟값 갱신은 단순하다.