본문 바로가기

Algorithm/BeakJoon

[BeakJoon 17471] 게리맨더링

안녕하세요. 오늘은 백준 17471 게리맨더링 문제를 풀어보도록 하겠습니다.

 

해당 문제는 

https://www.acmicpc.net/problem/17471

 

17471번: 게리맨더링

선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.

www.acmicpc.net

 

위 링크에서 확인하실 수 있습니다.

 

 

저는 다음과 같은 순서로 이 문제를 해결하였습니다.

 

1. 정해진 N의 개수만큼 두 집단으로 분리 

2. 분리되었다면 각각 연결되어 있는지 확인

3. 올바르게 분리 되었다면, 결과 갱신

 

1을 위해 저는 각 함수마다 두 개의 재귀 함수를 호출하여 주었습니다. 

각각 group을 A, B라 한다면 현재 idx의 노드가 A에 들어갈 경우, B에 들어갈 경우를 분리하여 재귀를 호출해주었습니다.

 

그다음 idx 가 N을 넘어갔다면, 모든 노드에 대한 분할이 완료되었다는 뜻이므로, 각 그룹이 모두 연결되어 있는지 확인했습니다. 해당 구현은 BFS를 통해 확인하였습니다.

 

두 집단 모두 정상적으로 연결되었다면, 최솟값을 갱신해 주었습니다.

 

* 추가로 그룹 분할의 케이스를 빠르게 진행하기 위해 비트마스킹을 활용하였습니다.

 

<소스 코드>

#include <bits/stdc++.h>
using namespace std;

int n, res=99999999;
int people[14], visited[14];
vector<int> graph[14];

bool check(int group) {
	fill(visited, visited+14, 1);
	int start = 1;
	for(int i = 1; i <= n; i++) {
		if(group&(1<<i)) visited[i] = 0, start=i;	
	}
	
	queue<int> q;
	q.push(start);
	visited[start] = 1;
	
	while(q.size()) {
		int here = q.front(); q.pop();
		
		for(int there : graph[here]) {
			if(!visited[there]) {
				visited[there] = 1;
				q.push(there);
			}
		}
	}
	
	for(int i = 0; i < 14; i++) if(visited[i] == 0) return false;
	return true;
}
int calc(int a, int b) {
	int ret1 = 0, ret2 = 0;
	for(int i = 1; i <= n; i++) 
		if(a&(1<<i)) ret1+=people[i];
		else if(b&(1<<i)) ret2+=people[i];
	
	return abs(ret2 - ret1);
}
void go(int idx, int groupA, int groupB) {
	if(idx > n) {
		if(check(groupA) && check(groupB)) res = min(res, calc(groupA, groupB));
		return;	
	}
	
	go(idx+1, groupA|(1<<idx), groupB);
	go(idx+1, groupA, groupB|(1<<idx));
	return;
}
int main(void) {
	ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
	cin >> n;
	
	for(int i = 1; i <= n; i++) cin >> people[i];
	for(int i = 1; i <= n; i++) {
		int a; cin >> a;
		for(int j = 0; j < a; j++) {
			int v; cin >> v;
			graph[i].push_back(v);
		}
	}
	
	go(1, 0, 0);
	if(res!=99999999) cout << res;
	else cout << -1;
	return 0;
}

 

*저의 글에 대한 피드백이나 지적은 언제나 환영합니다. 

'Algorithm > BeakJoon' 카테고리의 다른 글

[BeakJoon 20055] 컨베이어 벨트 위의 로봇  (0) 2021.10.18
[BeakJoon 19942] 다이어트  (0) 2021.09.26
[BeakJoon 2293] 동전 1  (0) 2021.09.08
[BeakJoon 2204] 동전 2  (0) 2021.09.08
BeakJoon 15591 MooTube (Silver)  (0) 2021.09.01