Problem Solving/BOJ(백준)
[BOJ]백준 17471번: 게리 맨더링
이진2
2019. 11. 13. 01:33
https://www.acmicpc.net/problem/17471
17471번: 게리맨더링
선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.
www.acmicpc.net
완전탐색으로 그래프를 두 구로 나누어 각각 연결요소의 개수를 구하고, 2개일 경우에만 차이의 최솟값을 구하는 문제
크게 세 부분으로 나뉜다.
1. N개의 구를 두 진영으로 나누는 경우의 수 구하기
2. 각각의 요소들을 BFS로 연결요소가 두 개인지 구하기
3. 두 연결요소의 차의 최솟값 구하기
일단
1. 백트래킹을 이용해서 depth가 N일 때 까지 콜스택을 쌓고
2. 1번 요소에서 BFS를 돌려서 전부 visit됐다면? / 그 다음 요소에서 BFS했는데 visit되지 않은 요소가 있다면? -> Fail
3. ans값 갱신
많이 어렵지는 않은 문제였다
#include <cstdio>
#include <queue>
using namespace std;
int n, p[11], ans=10000000;
bool graph[11][11], gu[11], visit[11];
queue<int> q;
int bfs(int num) {
int k = 1;
visit[num] = true;
q.push(num);
while (!q.empty()) {
int cur = q.front(); q.pop();
for (int t = 1; t <= n; t++) {
if (graph[cur][t] && !visit[t] && gu[cur] == gu[t]) {
visit[t] = true;
q.push(t); k++;
}
}
}
return k;
}
void func(int dep) {
if (dep > n) {
int red = 0, blue = 0, sub,j;
for (int i = 1; i <= n; i++)visit[i] = false;
red = bfs(1);
if (red == n)return;
for (j = 2; j <= n; j++)
if (!visit[j]) {
blue=bfs(j); break;
}
if (red + blue != n)return;
red = blue = 0;
for (int i = 1; i <= n; i++)
if (gu[i])red += p[i];
else blue += p[i];
sub = red > blue ? red - blue : blue - red;
ans = sub < ans ? sub : ans;
return;
}
gu[dep] = 0;
func(dep + 1);
gu[dep] = 1;
func(dep + 1);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)scanf("%d", &p[i]);
for (int i = 1,t,j; i <= n; i++) {
scanf("%d", &t);
while (t--) {
scanf("%d", &j);
graph[i][j] = true;
graph[j][i] = true;
}
}
func(1);
printf("%d", ans==10000000?-1:ans);
return 0;
}