문제
https://www.acmicpc.net/problem/14889
문제 요약
n명의 사람을 절반으로 나누어 스타트 팀과 링크 팀을 만든다.
S[i][j]는 i번 사람과 j번 사람이 같은 팀에 속해 있을 때, 팀에 더해지는 능력치이다.
(S[i][j]와 S[j][i]는 다를 수 있다.)
n과 S[i][j]가 모두 주어졌을 때, 스타트 팀과 링크 팀의 능력치 차이의 최솟값을 출력한다.
코드
#include <iostream>
#include <algorithm>
#define MAX_N 20
using namespace std;
int n;
int S[MAX_N][MAX_N];
// 최소 차이
int res = 1e9;
// i번 사람이 선택 되었는지
bool selected[MAX_N];
// 각 팀의 능력치 계산 후 차이의 최솟값을 갱신하는 함수
void update() {
int sum_a = 0;
int sum_b = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (selected[i] && selected[j]) {
sum_a += S[i][j];
}
else if (!selected[i] && !selected[j]) {
sum_b += S[i][j];
}
}
}
int diff = abs(sum_a - sum_b);
res = min(res, diff);
}
// 현재 cnt명으로 팀을 구성했고, idx번부터 팀으로 포함시키는 경우를 탐색하는 함수
void dfs(int cnt, int idx) {
// 팀원을 모두 고른 경우
if (cnt == n / 2) {
update(); // 능력치 계산
return;
}
// 가능한 범위에서 다음 사람을 골라 팀을 꾸려보기
for (int i = idx; i < n; i++) {
selected[i] = true;
dfs(cnt + 1, i + 1);
selected[i] = false;
}
}
int main() {
// 입력
cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> S[i][j];
}
}
// 완전탐색(백트래킹)을 통해 팀을 만들 수 있는 모든 경우의 수 탐색
dfs(0, 0);
// 출력
cout << res;
return 0;
}
코드 설명
1. n과 S[i][j]를 입력 받는다.
2. 함수 dfs를 선언하고, 팀이 가능한 모든 경우의 수를 완전탐색(백트래킹)한다.
+ 한 팀만 결정하면, 다른 팀은 자동으로 구성된다.
2 - 1. 팀원을 모두 고른 경우, 그 때 두 팀의 능력치를 계산하여 비교하고, 차이를 갱신한다.
2 - 2. 팀원을 더 골라야 하는 경우, 다음 번호 사람들을 골라 팀이 가능한지 재귀적으로 탐색한다.
3. 최소 차이를 출력한다.
고찰
오랜만에 백트래킹을 구현했더니, 생각보다 잘 되지 않았다.
좀 더 많은 연습이 필요하다!!
'Algorithm Problems > 완전 탐색' 카테고리의 다른 글
[백준/C++] 25602번: 캔 주기 (1) | 2024.07.05 |
---|---|
[백준/C++] 2529번: 부등호 (0) | 2024.07.03 |
[백준/C++] 1759번: 암호 만들기 (1) | 2024.05.09 |
[백준/C++] 1535번: 안녕 (1) | 2024.04.10 |
[백준/C++] 18428번: 감시 피하기 (0) | 2024.03.17 |