https://www.acmicpc.net/problem/2961
[문제]
도영이는 짜파구리 요리사로 명성을 날렸었다. 이번에는 이전에 없었던 새로운 요리에 도전을 해보려고 한다. 지금 도영이의 앞에는 재료가 N개 있다. 도영이는 각 재료의 신맛 S와 쓴맛 B를 알고 있다. 여러 재료를 이용해서 요리할 때, 그 음식의 신맛은 사용한 재료의 신맛의 곱이고, 쓴맛은 합이다.
시거나 쓴 음식을 좋아하는 사람은 많지 않다. 도영이는 재료를 적절히 섞어서 요리의 신맛과 쓴맛의 차이를 작게 만들려고 한다. 또, 물을 요리라고 할 수는 없기 때문에, 재료는 적어도 하나 사용해야 한다. 재료의 신맛과 쓴맛이 주어졌을 때, 신맛과 쓴맛의 차이가 가장 작은 요리를 만드는 프로그램을 작성하시오.
[입력 조건]
첫째 줄에 재료의 개수 N(1 ≤ N ≤ 10)이 주어진다. 다음 N개 줄에는 그 재료의 신맛과 쓴맛이 공백으로 구분되어 주어진다. 모든 재료를 사용해서 요리를 만들었을 때, 그 요리의 신맛과 쓴맛은 모두 1,000,000,000보다 작은 양의 정수이다.
[코드]
import java.util.*;
public class BaekJoon_2961 {
static int n,min=Integer.MAX_VALUE;
static int[][] food;
static boolean[] visited;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
food=new int[n][2];
visited=new boolean[n];
for(int i=0;i<n;i++) {
food[i][0]=sc.nextInt(); // 쓴 맛
food[i][1]=sc.nextInt(); // 단 맛
}
dfs(0);
System.out.println(min);
}
static void dfs(int depth) {
if(depth==food.length) {
int sour=1;
int butter=0;
int count=0;
for(int i=0;i<visited.length;i++) {
if(visited[i]) {
count++;
sour*=food[i][0]; // 쓴맛
butter+=food[i][1]; // 단맛
}
}
// 아무 음식도 선택되지 않은 경우는 return
if(count==0)
return;
// 최솟값 갱신
min=Math.min(min, Math.abs(butter-sour));
return;
}
// 현재 음식은 선택한 경우 탐색
visited[depth]=true;
dfs(depth+1);
// 현재 음식은 선택하지 않은 경우 탐색
visited[depth]=false;
dfs(depth+1);
}
}
[고찰]
이번 문제는 음식을 1개부터 n개까지 선택 할 수 있는 모든 경우의 수를 탐색하여 그 중 신맛과 단맛의 조화가 가장 최소가 되는 경우를 찾는 문제였다. 선택해야 하는 음식의 개수와 종류가 달라지기 때문에 어떻게 모든 경우를 탐색할 수 있을까 고민해보았다. 그 결과 이번 문제를 푸는 핵심은 '현재 음식을 선택하냐 선택하지 않느냐' 였다. 이를 백트래킹으로 구현하면 쉽게 해결할 수 있다. 현재 음식을 선택한 채로 깊이를 1 늘려 재귀호출 하거나 현재 음식을 선택하지 않은 채로 깊이를 1 늘려 재귀호출 하면 된다. 깊이가 음식의 개수와 같아진다면 선태된 음식의 신맛과 단맛을 계산해 최솟값을 갱신해주면 된다.
'백준' 카테고리의 다른 글
[백준_2023번] 신기한 소수 (0) | 2021.08.27 |
---|---|
[백준_16198번] 에너지 모으기 (0) | 2021.08.27 |
[백준_16922번] 로마 숫자 만들기 (0) | 2021.08.25 |
[백준_11559번] Puyo Puyo (0) | 2021.08.25 |
[백준_11057번] 오르막 수 (0) | 2021.08.25 |