코딩테스트/SWEA
[SWEA] 4012번 - 요리사 풀이 및 코드 분석 (Java)
by 현걸
2025. 2. 28.
문제 링크
1. 문제 분석
📌 문제 개요
N
개의 재료를 N/2
개씩 두 그룹으로 나누어 요리를 만든다.
- 두 요리의 맛의 차이가 최소가 되도록 재료를 배분해야 한다.
- 각 재료
i
와 j
가 함께 사용되면 시너지(Sij)가 발생한다.
- 두 요리의 맛 차이 |A - B| 를 최소화하는 경우를 찾는다.
🎯 요구사항
- N개의 재료를 두 개의 요리에
N/2
개씩 배분해야 한다.
- 각 요리의 맛을 계산하여 두 음식의 맛 차이가 최소가 되도록 한다.
- 완전 탐색(백트래킹)으로 모든 경우를 조사해야 한다.
2. 해결 방법
🔹 핵심 개념
- 조합(combination) 을 이용하여
N/2
개의 재료를 선택하여 요리 A를 만든다.
- 선택되지 않은 재료들로 요리 B를 만든다.
- 각 요리의 맛을 계산하여 차이를 최소화한다.
- 백트래킹을 활용하여 최적의 조합을 찾는다.
🔑 해결 절차
- 모든 가능한 재료 조합을 완전 탐색
comb()
을 이용하여 N
개의 재료 중 N/2
개를 선택
- 선택된
A
를 제외한 나머지 재료는 B
그룹이 된다.
- 각 요리의 맛을 계산
calFood()
에서 sumA
와 sumB
를 계산
Sij
와 Sji
를 합산하여 시너지를 계산
- 맛 차이가 최소가 되는 경우를 갱신
answer = min(answer, |sumA - sumB|)
3. 코드 구현
import java.io.*;
import java.util.*;
public class Solution {
static int N, answer;
static ArrayList<Integer> A;
static int[][] S;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
for (int t = 1; t <= T; t++) {
sb.append("#").append(t).append(" ");
answer = Integer.MAX_VALUE;
N = Integer.parseInt(br.readLine());
S = new int[N][N];
for (int r = 0; r < N; r++) {
st = new StringTokenizer(br.readLine());
for (int c = 0; c < N; c++) {
S[r][c] = Integer.parseInt(st.nextToken());
}
}
A = new ArrayList<>();
comb(0);
sb.append(answer).append("\n");
}
System.out.println(sb);
}
// 백트래킹을 이용한 조합 탐색
private static void comb(int d) {
if (A.size() == N / 2) {
calFood();
return;
}
for (int i = d; i < N; i++) {
A.add(i);
comb(i + 1);
A.remove(A.size() - 1);
}
}
// A 요리를 선택한 후, B 요리를 만들어 맛 차이 계산
private static void calFood() {
ArrayList<Integer> B = new ArrayList<>();
int sumA = 0, sumB = 0;
for (int i = 0; i < N; i++) {
if (!A.contains(i)) {
B.add(i);
}
}
// A 요리의 시너지 계산
for (int i = 0; i < A.size(); i++) {
for (int j = 0; j < A.size(); j++) {
sumA += S[A.get(i)][A.get(j)];
}
}
// B 요리의 시너지 계산
for (int i = 0; i < B.size(); i++) {
for (int j = 0; j < B.size(); j++) {
sumB += S[B.get(i)][B.get(j)];
}
}
answer = Math.min(answer, Math.abs(sumA - sumB));
}
}
4. 코드 분석
🔹 주요 알고리즘
- 백트래킹을 활용한 조합 탐색
N
개의 재료 중 N/2
개를 선택하는 모든 조합을 생성
- 이미 선택된 경우 탐색을 중단하여 중복 계산을 방지
- 두 음식의 맛 계산
Sij
와 Sji
를 합산하여 각 음식의 총 시너지 값을 계산
- 두 음식의 맛 차이를 계산하여 최소값을 갱신
🔹 시간 복잡도 분석
- 조합 생성:
O(2^N)
- 각 조합에서 시너지 계산:
O(N^2)
- 최악의 경우 (
N=16
)
O(2^16 * 16^2) = O(65536 * 256) ≈ O(1.6 * 10^7)
- 백트래킹을 활용하면 충분히 해결 가능
5. 개선할 점 및 대체 방법
✅ 개선할 점
- 비트마스킹을 활용한 조합 최적화
N
이 작으므로 비트마스크를 활용하면 탐색 속도를 개선 가능
1 << N
을 활용하여 모든 조합을 빠르게 탐색 가능
- DP를 활용한 부분 문제 최적화
dp[A]
를 저장하면 중복 계산을 줄일 수 있음
🔄 대체 방법
- Bitmask DP 적용 가능
N
이 작으므로 bitmask
를 이용하면 탐색 속도 개선 가능
- DFS 활용 가능
DFS
를 사용하여 N/2
개의 조합을 선택하는 방식도 가능