코딩테스트/백준
[백준] 14889번 - 스타트와 링크 문제 풀이 및 코드 분석 (Java)
현걸
2025. 2. 21. 10:17
1. 문제 분석
문제 개요
- 총 N명의 사람이 있으며, N은 짝수이다.
- 사람들을 두 팀으로 나누어야 한다. (N/2명씩)
- 능력치 행렬 S[i][j]가 주어지며, i번과 j번 사람이 같은 팀일 때 팀의 능력치에 추가된다.
- 두 팀의 능력치 차이를 최소화하는 팀 구성을 찾아야 한다.
제약 조건
- 4 ≤ N ≤ 20이므로 완전 탐색(브루트포스)이 가능하지만, 효율적인 탐색 방법이 필요함.
- S[i][i] = 0이고, S[i][j] ≠ S[j][i]일 수 있다.
- 팀 구성 조합을 만들고, 각 팀의 능력치를 계산한 후, 차이가 최소인 경우를 찾는다.
2. 해결 방법
1) 조합을 이용한 팀 구성
- N명을 두 개의 그룹(N/2명씩)으로 나누어야 하므로 조합을 활용한다.
- 백트래킹을 이용하여 첫 번째 팀을 구성하고, 남은 인원은 자동으로 두 번째 팀이 된다.
2) 능력치 계산
- 선택된 팀원의 조합을 순회하며 능력치 합계를 구한다.
- 두 팀의 능력치 차이를 구한 후 최소값을 갱신한다.
3) 백트래킹을 통한 최적화
- 이미 선택된 인덱스를 활용하여 나머지 팀을 구하는 방식으로
other
배열을 사용한다.
3. 코드 구현
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int N, ans = Integer.MAX_VALUE;
static int[] nums;
static int[][] board;
private static void init() throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
board = new int[N][N];
for (int r = 0; r < N; r++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int c = 0; c < N; c++) {
board[r][c] = Integer.parseInt(st.nextToken());
}
}
}
private static void comb(int cnt, int start) {
if (cnt == N / 2) {
int power1 = 0, power2 = 0;
for (int i = 0; i < N / 2; i++) {
for (int j = 0; j < N / 2; j++) {
power1 += board[nums[i]][nums[j]];
}
}
int[] other = new int[N / 2];
int idx = 0, cur = 0;
for (int i = 0; i < N; i++) {
if (idx < N / 2 && i == nums[idx]) {
idx++;
} else {
other[cur++] = i;
}
}
for (int i = 0; i < N / 2; i++) {
for (int j = 0; j < N / 2; j++) {
power2 += board[other[i]][other[j]];
}
}
ans = Math.min(ans, Math.abs(power2 - power1));
return;
}
for (int i = start; i < N; i++) {
nums[cnt] = i;
comb(cnt + 1, i + 1);
}
}
public static void main(String[] args) throws Exception {
init();
nums = new int[N / 2];
comb(0, 0);
System.out.println(ans);
}
}
4. 코드 분석
1) 초기화 (init()
)
BufferedReader
를 사용하여 입력을 받는다.board
배열에 능력치 정보를 저장한다.
2) 조합을 이용한 팀 구성 (comb()
)
cnt
는 현재까지 선택한 인원 수,start
는 다음 선택 가능한 인덱스.N/2
명의 선수가 선택되면 두 팀의 능력치를 계산한다.- 능력치 차이를 구한 후 최소값을 갱신한다.
- 백트래킹을 사용하여 탐색을 줄인다.
3) 능력치 계산
nums
를 이용하여 선택된 팀원을 추적한다.other
배열을 활용하여 남은 팀원을 구성하고 능력치를 계산한다.
5. 개선할 점 및 대체 방법
1) other
배열 최적화
- 기존에는
other
배열을 만들고 인덱스를 관리했지만, 이를 더욱 효율적으로 구성할 방법을 고민해볼 수 있음.
2) 완전 탐색의 시간 복잡도 줄이기
N
이 20이므로 최대10C5 = 252
개의 조합을 탐색해야 하지만 백트래킹을 이용하여 불필요한 연산을 줄였다.
3) 대체 방법
- 비트마스킹을 활용한 방법:
N ≤ 20
이므로 비트마스킹을 활용하면 더 효율적인 탐색이 가능하다. - 동적 계획법(DP) 활용:
dp[state]
를 이용해 부분 문제를 저장하면 중복 계산을 줄일 수 있다.