티스토리 뷰

728x90

문제

재현시의 시장 구재현은 지난 몇 년간 게리맨더링을 통해서 자신의 당에게 유리하게 선거구를 획정했다. 견제할 권력이 없어진 구재현은 권력을 매우 부당하게 행사했고, 심지어는 시의 이름도 재현시로 변경했다. 이번 선거에서는 최대한 공평하게 선거구를 획정하려고 한다.

재현시는 크기가 N×N인 격자로 나타낼 수 있다. 격자의 각 칸은 구역을 의미하고, r행 c열에 있는 구역은 (r, c)로 나타낼 수 있다. 구역을 다섯 개의 선거구로 나눠야 하고, 각 구역은 다섯 선거구 중 하나에 포함되어야 한다. 선거구는 구역을 적어도 하나 포함해야 하고, 한 선거구에 포함되어 있는 구역은 모두 연결되어 있어야 한다. 구역 A에서 인접한 구역을 통해서 구역 B로 갈 수 있을 때, 두 구역은 연결되어 있다고 한다. 중간에 통하는 인접한 구역은 0개 이상이어야 하고, 모두 같은 선거구에 포함된 구역이어야 한다.

선거구를 나누는 방법은 다음과 같다.

  1. 기준점 (x, y)와 경계의 길이 d1, d2를 정한다. (d1, d2 ≥ 1, 1 ≤ x < x+d1+d2 ≤ N, 1 ≤ y-d1 < y < y+d2 ≤ N)
  2. 다음 칸은 경계선이다.
    1. (x, y), (x+1, y-1), ..., (x+d1, y-d1)
    2. (x, y), (x+1, y+1), ..., (x+d2, y+d2)
    3. (x+d1, y-d1), (x+d1+1, y-d1+1), ... (x+d1+d2, y-d1+d2)
    4. (x+d2, y+d2), (x+d2+1, y+d2-1), ..., (x+d2+d1, y+d2-d1)
  3. 경계선과 경계선의 안에 포함되어있는 곳은 5번 선거구이다.
  4. 5번 선거구에 포함되지 않은 구역 (r, c)의 선거구 번호는 다음 기준을 따른다.
    • 1번 선거구: 1 ≤ r < x+d1, 1 ≤ c ≤ y
    • 2번 선거구: 1 ≤ r ≤ x+d2, y < c ≤ N
    • 3번 선거구: x+d1 ≤ r ≤ N, 1 ≤ c < y-d1+d2
    • 4번 선거구: x+d2 < r ≤ N, y-d1+d2 ≤ c ≤ N

아래는 크기가 7×7인 재현시를 다섯 개의 선거구로 나눈 방법의 예시이다.

구역 (r, c)의 인구는 A[r][c]이고, 선거구의 인구는 선거구에 포함된 구역의 인구를 모두 합한 값이다. 선거구를 나누는 방법 중에서, 인구가 가장 많은 선거구와 가장 적은 선거구의 인구 차이의 최솟값을 구해보자.

 

입력

첫째 줄에 재현시의 크기 N이 주어진다.

둘째 줄부터 N개의 줄에 N개의 정수가 주어진다. r행 c열의 정수는 A[r][c]를 의미한다.

 

출력

첫째 줄에 인구가 가장 많은 선거구와 가장 적은 선거구의 인구 차이의 최솟값을 출력한다.

 

제한

  • 5 ≤ N ≤ 20
  • 1 ≤ A[r][c] ≤ 100

 

코드

#include <iostream>
#include <cstring>

using namespace std;

int N;
int A[21][21];			// 구역의 인구
bool boundary[21][21];		// 경계선
int population[6];		// 선거구의 인구
int sum;			// 총 인구

void find_boundary(int x, int y, int d1, int d2)
{
	int d;

	for (d = 0; d <= d1; d++)
	{
		boundary[x + d][y - d] = true;
		boundary[x + d2 + d][y + d2 - d] = true;
	}
	for (d = 0; d <= d2; d++)
	{
		boundary[x + d][y + d] = true;
		boundary[x + d1 + d][y - d1 + d] = true;
	}
}

void get_population(int x, int y, int d1, int d2)
{
	int r, c;

	population[5] = sum;
	for (r = 1; r < x + d1; r++)
	{
		for (c = 1; c <= y; c++)
		{
			if (boundary[r][c])
				break;
			population[1] += A[r][c];
		}
	}
	population[5] -= population[1];
	for (r = 1; r <= x + d2; r++)
	{
		for (c = N; c > y; c--)
		{
			if (boundary[r][c])
				break;
			population[2] += A[r][c];
		}
	}
	population[5] -= population[2];
	for (r = N; r >= x + d1; r--)
	{
		for (c = 1; c < y - d1 + d2; c++)
		{
			if (boundary[r][c])
				break;
			population[3] += A[r][c];
		}
	}
	population[5] -= population[3];
	for (r = N; r > x + d2; r--)
	{
		for (c = N; c >= y - d1 + d2; c--)
		{
			if (boundary[r][c])
				break;
			population[4] += A[r][c];
		}
	}
	population[5] -= population[4];
}

int get_gap()
{
	int min_value = 2e9;
	int max_value = 0;
	int i, res;

	for (i = 1; i <= 5; i++)
	{
		min_value = min(min_value, population[i]);
		max_value = max(max_value, population[i]);
	}
	res = max_value - min_value;
	return res;
}

int solution()
{
	int x, y;
	int d1, d2;
	int res = 2e9;

	for (x = 1; x <= N; x++)
	{
		for (y = 1; y <= N; y++)
		{
			for (d1 = 1; d1 <= y - 1; d1++)
			{
				for (d2 = 1; d2 <= N - y; d2++)
				{
					if (d1 + d2 <= N - x)
					{
						memset(boundary, 0, sizeof(boundary));
						memset(population, 0, sizeof(population));
						find_boundary(x, y, d1, d2);
						get_population(x, y, d1, d2);
						res = min(res, get_gap());
					}
				}
			}
		}
	}
	return res;
}

int main()
{
	int r, c;
	
	cin >> N;
	for (r = 1; r <= N; r++)
	{
		for (c = 1; c <= N; c++)
		{
			cin >> A[r][c];
			sum += A[r][c];
		}
	}
	cout << solution() << endl;
	return 0;
}

 

명시된 조건에 의해 d1과 d2가 1 이상인 수라는 것을 알고 있다. x와 y의 범위에서 d1과 d2의 최댓값을 정의할 수 있다. 1 y - d1에서 1 d1  y - 1인 것을 알 수 있고, y + d2 N에서 1  d2  N - y인 것을 알 수 있다. 또한 x + d1 + d2 ≤ N에서 d1 + d2 ≤ N - x를 만족해야 하는 것을 알 수 있다. solution() 함수에서는 이 범위 내에서 가능한 모든 x, y, d1, d2의 조합에 대해 find_boundary() 함수로 경계선을 찾아 선거구를 나눈다.

 

선거구는 다음 그림과 같이 나뉜다. 경계선의 네 변은 항상 대각선이므로 꼭짓점에 해당하는 구역은 항상 같은 선거구에 속하게 된다. (1, 1)은 1번 선거구, (1, N)은 2번 선거구, (N, 1)은 3번 선거구, (N, N)은 4번 선거구에 포함된다. get_population() 함수에서는 이 구역(꼭짓점)부터 시작해서 각 구역의 인구를 더해 선거구의 인구를 구한다. 반복문의 범위는 문제에서 주어진 조건과 동일하게 설정하고, 한 행을 확인하는 도중 경계선을 만나면 다음 행으로 넘어간다. 이렇게 1, 2, 3, 4번 선거구의 인구를 구하면 다음 식을 이용해 5번 선거구의 인구를 구할 수 있다. 총 인구는 입력을 받을 때 각 구역의 인구를 누적한 변수 sum이다.
(총 인구) - (1, 2, 3, 4번 선거구의 인구의 합) = (5번 선거구의 인구)

x = 3, y = 6, d1 = 3, d2 = 2

이제 get_gap() 함수에서 다섯개의 선거구 중 인구가 가장 많은 선거구와 가장 적은 선거구를 찾고 그 차이를 구하고 최솟값을 갱신한다.

 

링크

 

17779번: 게리맨더링 2

재현시의 시장 구재현은 지난 몇 년간 게리맨더링을 통해서 자신의 당에게 유리하게 선거구를 획정했다. 견제할 권력이 없어진 구재현은 권력을 매우 부당하게 행사했고, 심지어는 시의 이름

www.acmicpc.net

 

inbdni/Baekjoon

Contribute to inbdni/Baekjoon development by creating an account on GitHub.

github.com

 

728x90
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
공지사항
링크
Total
Today
Yesterday