문제
재현시의 시장 구재현은 지난 몇 년간 게리맨더링을 통해서 자신의 당에게 유리하게 선거구를 획정했다. 견제할 권력이 없어진 구재현은 권력을 매우 부당하게 행사했고, 심지어는 시의 이름도 재현시로 변경했다. 이번 선거에서는 최대한 공평하게 선거구를 획정하려고 한다.
재현시는 크기가 N×N인 격자로 나타낼 수 있다. 격자의 각 칸은 구역을 의미하고, r행 c열에 있는 구역은 (r, c)로 나타낼 수 있다. 구역을 다섯 개의 선거구로 나눠야 하고, 각 구역은 다섯 선거구 중 하나에 포함되어야 한다. 선거구는 구역을 적어도 하나 포함해야 하고, 한 선거구에 포함되어 있는 구역은 모두 연결되어 있어야 한다. 구역 A에서 인접한 구역을 통해서 구역 B로 갈 수 있을 때, 두 구역은 연결되어 있다고 한다. 중간에 통하는 인접한 구역은 0개 이상이어야 하고, 모두 같은 선거구에 포함된 구역이어야 한다.
선거구를 나누는 방법은 다음과 같다.
- 기준점 (x, y)와 경계의 길이 d1, d2를 정한다. (d1, d2 ≥ 1, 1 ≤ x < x+d1+d2 ≤ N, 1 ≤ y-d1 < y < y+d2 ≤ N)
- 다음 칸은 경계선이다.
- (x, y), (x+1, y-1), ..., (x+d1, y-d1)
- (x, y), (x+1, y+1), ..., (x+d2, y+d2)
- (x+d1, y-d1), (x+d1+1, y-d1+1), ... (x+d1+d2, y-d1+d2)
- (x+d2, y+d2), (x+d2+1, y+d2-1), ..., (x+d2+d1, y+d2-d1)
- 경계선과 경계선의 안에 포함되어있는 곳은 5번 선거구이다.
- 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인 재현시를 다섯 개의 선거구로 나눈 방법의 예시이다.
x = 2, y = 4, d1 = 2, d2 = 2 | x = 2, y = 5, d1 = 3, d2 = 2 | x = 4, y = 3, d1 = 1, d2 = 1 |
구역 (r, c)의 인구는 A[r][c]이고, 선거구의 인구는 선거구에 포함된 구역의 인구를 모두 합한 값이다. 선거구를 나누는 방법 중에서, 인구가 가장 많은 선거구와 가장 적은 선거구의 인구 차이의 최솟값을 구해보자.
입력
첫째 줄에 재현시의 크기 N이 주어진다.
둘째 줄부터 N개의 줄에 N개의 정수가 주어진다. r행 c열의 정수는 A[r][c]를 의미한다.
출력
첫째 줄에 인구가 가장 많은 선거구와 가장 적은 선거구의 인구 차이의 최솟값을 출력한다.
제한
- 5 ≤ N ≤ 20
- 1 ≤ A[r][c] ≤ 100
예제 입력 1
6
1 2 3 4 1 6
7 8 9 1 4 2
2 3 4 1 1 3
6 6 6 6 9 4
9 1 9 1 9 5
1 1 1 1 9 9
예제 출력 1
18
예제 입력 2
6
5 5 5 5 5 5
5 5 5 5 5 5
5 5 5 5 5 5
5 5 5 5 5 5
5 5 5 5 5 5
5 5 5 5 5 5
예제 출력 2
20
예제 입력 3
8
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9 1
4 5 6 7 8 9 1 2
5 6 7 8 9 1 2 3
6 7 8 9 1 2 3 4
7 8 9 1 2 3 4 5
8 9 1 2 3 4 5 6
예제 출력 3
23
알고리즘 분류
- 구현
- 브루트포스 알고리즘
- 시뮬레이션
풀이
선거구 전원을 5번 선거구로 우선 설정한다.
우선 기준을 (R, C)라고 한다.
1번 선거구는 Y좌표는 1부터 R + D1까지 , X좌표는 1부터 C까지를 범위로 하는데, Y좌표가 R 이상이라면 1번 선거구로 지정할 X좌표를 1개씩 줄인다.
2, 3, 4번 선거구도, 기준에 따라서 정해주면 자동적으로 5번 선거구 역시 정해지게 된다.
이제 1~5번 선거구에 속해 있는 사람들을 구해서, 가장 많은 사람을 보유한 선거구와 가장 적은 사람을 보유한 선거구의 차이의 최솟값을 구한다.
코드
#include <iostream>
#include <string>
#include <cmath>
#include <stack>
#include <vector>
#include <algorithm>
#define FIRST cin.tie(NULL); cout.tie(NULL); ios::sync_with_stdio(false);
#define MAX 25
#define INF 2e9
using namespace std;
int N;
int MAP[MAX][MAX];
int Region[MAX][MAX];
int answer = INF;
int answer_MAP[MAX][MAX];
void init() {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
Region[i][j] = 5;
}
}
}
void Region_Arrange(int Y, int X, int D1, int D2) {
// 모든 선거구를 5번으로 채운다.
init();
// 다음은 1번 선거구를 채운다.
int Sub_Area = 0;
for (int i = 1; i < Y + D1; i++) {
if (i >= Y) {
Sub_Area++;
}
for (int j = 1; j <= X - Sub_Area; j++) {
Region[i][j] = 1;
}
}
// 다음은 2번 선거구를 채운다.
Sub_Area = 0;
for (int j = N; j > X; j--) {
if (j <= X + D2) {
Sub_Area++;
}
for (int i = 1; i <= Y + D2 - Sub_Area; i++) {
Region[i][j] = 2;
}
}
// 다음은 3번 선거구를 채운다.
Sub_Area = 0;
for (int j = 1; j < X - D1 + D2; j++) {
if (j >= X - D1) {
Sub_Area++;
}
for (int i = N; i >= Y + D1 + Sub_Area; i--) {
Region[i][j] = 3;
}
}
// 다음은 4번 선거구를 채운다.
Sub_Area = 0;
for (int i = N; i > Y + D2; i--) {
if (i <= Y + D1 + D2) {
Sub_Area++;
}
for (int j = N; j >= X - D1 + D2 + Sub_Area; j--) {
Region[i][j] = 4;
}
}
}
void Find_Answer() {
int People[6] = { -1,0,0,0,0,0 };
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
People[Region[i][j]] += MAP[i][j];
}
}
sort(People, People + 6);
if (answer > People[5] - People[1]) {
answer = People[5] - People[1];
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
answer_MAP[i][j] = Region[i][j];
}
}
}
}
bool First_Condition(int D1, int D2) {
if ((D1 >= 1) && (D2 >= 1)) {
return true;
}
return false;
}
bool Second_Condition(int Y, int D1, int D2) {
if ((Y >= 1) && (Y < Y + D1 + D2) && (Y + D1 + D2 <= N)) {
return true;
}
return false;
}
bool Third_Condition(int X, int D1, int D2) {
if ((X - D1 >= 1) && (X - D1 < X) && (X < X + D2) && (X + D2 <= N)) {
return true;
}
return false;
}
int main() {
FIRST
cin >> N;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
cin >> MAP[i][j];
}
}
for (int Y = 1; Y <= N; Y++) {
for (int X = 2; X <= N; X++) {
for (int D1 = 1; D1 <= X; D1++) {
for (int D2 = 1; D2 < N - X; D2++) {
if (First_Condition(D1, D2) && Second_Condition(Y, D1, D2) && Third_Condition(X, D1, D2)) {
Region_Arrange(Y, X, D1, D2);
Find_Answer();
}
}
}
}
}
cout << answer << "\n";
return 0;
}
'BOJ > Gold' 카테고리의 다른 글
[BOJ/Gold 3] 백준 3425 고스택(C++) (0) | 2022.01.10 |
---|---|
[BOJ/Gold 2] 백준 2136 개미(C++) (0) | 2022.01.10 |
[BOJ/Gold 4] 백준 2116 주사위 쌓기(C++) (0) | 2022.01.10 |
[BOJ/Gold 4] 백준 14499 주사위 굴리기(C++) (0) | 2022.01.10 |
[BOJ/Gold 3] 백준 20057 마법사 상어와 토네이도(C++) (0) | 2022.01.10 |