본문 바로가기

algorithm/BOJ

백준 17471_게리맨더링(C++)

 

www.acmicpc.net/problem/17471

 

17471번: 게리맨더링

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

www.acmicpc.net

[문제 풀이]

브루트 포스(Brute force)를 이용하여 문제를 풀었습니다.

 

이 문제는 주어진 입력을 두 집합으로 나누었을 때 나누어진 집합이 그래프로 연결 되어 있는지를 찾는 문제였습니다. 예를 들어 두 집합 A ={ 1, 2, 3 }, B = { 4, 5, 6 }으로 나누었을 때 A의 노드들이 A의 노드를 통해서 모두 연결 되어 있어야 합니다. 반대로 B 또한 마찬가지입니다.

 

파란색 집합의 원소 5가 B의 노드를 통해 6으로 갈 수 없으므로 아래의 그림은 불가능한 방법입니다.

 

 

또한, 두 집합 중 한 집합이라도 공집합이면 안됩니다.

 

 

로직 설명

  • 도시를 두 구역으로 나눕니다.
  • 나누어진 구역끼리 연결 되어 있는지 확인합니다.
  • 연결 되어 있다면 값을 비교해 줍니다.

[코드]

#include<iostream>
#include<math.h>

using namespace std;

int N, answer = 987654321;

int population[11] = { 0, };
int map[11][11] = { 0, };
int visit[11] = { 0, };
int connect_city[11];

void Connect(int idx, int check) {//도시 연결

	for (int j = 1; j <= N; j++)
		if (map[idx][j] == 1 && visit[j] == check && connect_city[j] == 2) {
			connect_city[j] = check;
			Connect(j, check);
		}


}

bool ConnectCheck() {//도시 연결 여부 확인

	for (int i = 1; i <= N; i++)
		connect_city[i] = 2;

	for (int i = 1; i <= N; i++)
		if (visit[i] == 1) {
			connect_city[i] = 1;
			Connect(i, 1);
			break;
		}

	for (int i = 1; i <= N; i++)
		if (visit[i] == 0) {
			connect_city[i] = 0;
			Connect(i, 0);
			break;
		}

	for (int i = 1; i <= N; i++)
		if (connect_city[i] != visit[i])
			return false;

	return true;

}

void Divide(int num, int total, int a_total) {

	if (num == total) {
		if (ConnectCheck()) {//인구 수 비교
			int b_total = 0;

			for (int i = 1; i <= N; i++)
				if (visit[i] == 0)
					b_total += population[i];

			if (answer > abs(a_total - b_total))
				answer = abs(a_total - b_total);

		}
		return;
	}

	for (int i = 1; i <= N; i++) {

		if (visit[i] == 0) {

			visit[i] = 1;
			Divide(num + 1, total, a_total + population[i]);
			visit[i] = 0;

		}

	}

}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(NULL);

	cin >> N;

	for (int i = 1; i <= N; i++) 
		cin >> population[i];

	for (int i = 1; i <= N; i++) {
		int number; cin >> number;

		for (int j = 0; j < number; j++) {
			int temp; cin >> temp;

			map[i][temp] = 1;
		}
	}

	for (int i = 1; i <= N / 2; i++) //도시 나누기
		Divide(0, i, 0);

	if (answer == 987654321)
		cout << -1 << endl;
	else
		cout << answer << endl;

	return 0;

}

 

 

'algorithm > BOJ' 카테고리의 다른 글

백준 1926_그림(JAVA)  (0) 2021.04.14
백준 2583_영역 구하기(JAVA)  (0) 2021.04.09
백준 2668_숫자고르기(C++)  (0) 2020.11.04
백준 17070_파이프 옮기기 1(C++)  (0) 2020.10.31
백준 16637_괄호 추가하기(C++)  (0) 2020.10.31