일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- boj 2178
- 백준 2167
- 2636
- 백준 19238
- 백준 1697
- boj 2470
- boj 2635
- 백준 1503
- 백준 2178
- boj 2636
- boj 2661
- boj 1503
- boj 2167
- boj 2108
- 백준 2635
- boj 19238
- boj 2206
- 백준 2206
- 2167
- 백준 10800
- 10800
- boj 1697
- boj 2667
- 백준 2470
- boj 10800
- 백준 2661
- boj 1806
- 백준 2636
- 백준 1806
- 백준 2108
- Today
- Total
말랑말랑한 개발자 이야기
[백준 17779번] 게리맨더링2 본문
[백준 17779번] 게리맨더링2
문제
재현시의 시장 구재현은 지난 몇 년간 게리맨더링을 통해서 자신의 당에게 유리하게 선거구를 획정했다. 견제할 권력이 없어진 구재현은 권력을 매우 부당하게 행사했고, 심지어는 시의 이름도 재현시로 변경했다. 이번 선거에서는 최대한 공평하게 선거구를 획정하려고 한다.
재현시는 크기가 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
출력
첫째 줄에 인구가 가장 많은 선거구와 가장 적은 선거구의 인구 차이의 최솟값을 출력한다.
풀이
#include <iostream>
#include <algorithm>
using namespace std;
int N, arr[21][21];
int target = 2100000000;
void solve(int x, int y, int d1, int d2){
int v[5] = {0,};
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
if(i < x + d1 && j <= y && !(i >= x && j >= y - (i-x))) v[0] += arr[i][j];
else if(i <= x + d2 && j > y && !(i >= x && j <= y + (i-x))) v[1] += arr[i][j];
else if(i >= x + d1 && j < y-d1+d2 && !(i <= x+d1+d2 && j >= y-d1+d2 + (i-(x+d1+d2)))) v[2] += arr[i][j];
else if(i > x + d2 && j >= y-d1+d2 && !(i <= x+d1+d2 && j <= y-d1+d2 - (i-(x+d1+d2)))) v[3] += arr[i][j];
else v[4] += arr[i][j];
}
}
sort(v, v+5);
target = min(target, v[4]-v[0]);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> N;
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
cin >> arr[i][j];
}
}
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
for(int k=1;i+k < N && j-k >= 0; k++){
for(int m=1; i+m < N && j+m < N; m++){
solve(i,j,k,m);
}
}
}
}
cout << target;
return 0;
}
5/18일자 세번째 문제, 보자마자 들었던 생각은 쉽겠다였다. N이 최대 20이기 때문에 모든 경우에 대해 체크 해봐도 O(20^4)로 충분히 가능하다고 생각하고 시도했다. 문제는 선거구를 나누는데있어 조건에 맞게 범위를 나누어야 하는데 생각보다 어려웠다. 어거지로 풀고나서 다시 보면서 든 생각은 위 문제를 특정 점에서 왼쪽아래, 오른쪽아래로 다이아몬드를 구성하는게 아닌 다이아몬드의 중심점에서 시작한다는 생각으로 재구성해서 풀었으면 더 쉽게 풀었을 것 같는 생각이 든다. 무튼 힘들게 풀었는데 알고보니 삼성 역량테스트 기출문제였다. 뭔가 위안이 된다.. 여러번 다시 보면서 다이아몬드 형식의 범위 체크를 기억 해 두어야겠다.
'알고리즘 > 백준' 카테고리의 다른 글
[백준 9024번] 두 수의 합 (0) | 2021.05.23 |
---|---|
[백준 14430번] 자원 캐기 (0) | 2021.05.23 |
[백준 5557번] 1학년 (0) | 2021.05.18 |
[백준 19947번] 투자의 귀재 배주형 (0) | 2021.05.18 |
[백준 16174번] 점프왕 쩰리 (Large) (0) | 2021.05.17 |