게리맨더링 2
문제 해석
- 5개의 선거구로 나누어서 인구가 가장 많은 선거구와 가장 적은 선거구의 차이의 최솟값을 구하는 문제입니다.
- 먼저 기준점(x,y)와 길이 d1,d2를 정합니다.
- 선거구의 경계는 다음과 같습니다.
- (x,y),(x+1,y-1),…,(x+d1,y-d1)
- (x,y),(x+1,y+1),…,(x+d1,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+d201),…,(d+d2+d1,y+d2-d1)
- 위의 경계선과 경계선 안의 범위는 모두 5번 선거구입니다.
- 나머지 구역은 다음 기준을 따라서 결정됩니다.
- 1<=r < x+ d1, 1<=c <=y
- 1<=r <= x+d1, y< c <=N
- x+d1 <= r <= N, 1<= c < y-d1+d2
- x+d2 < r <=N, y-d1+d2 <=c <=N
설계(20)
- 완전탐색문제입니다.
- 먼저 x,y,d1,d2를 정합니다.
- 그 후, 선거구를 정합니다.
- 선거구를 정할 때, 모든 좌표를 5로 초기화한 후 시작합니다.
- 주어지는 조건에 따라서 선거구를 정하고, 각 선거구의 인구수를 모두 더해줍니다.
구현(50)
코드
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 21
#define INF 987654321
int map[MAXN][MAXN];
int tmp_arr[MAXN][MAXN];
int num[6];
int N;
int ans = INF;
int go(int x, int y, int d1, int d2){
memset(tmp_arr,0,sizeof(tmp_arr));
memset(num,0,sizeof(num));
int max_num = 0;
int min_num = INF;
for (int i =1 ; i <=N; i++){
for (int j= 1 ;j<=N; j++){
tmp_arr[i][j] = 5;
}
}
// 1번 선거구
int cnt = 0;
for (int i = 1; i< x+d1; i++){
if (i>=x) cnt++;
for (int j = 1; j <= y-cnt; j++){
tmp_arr[i][j] = 1;
}
}
// 2번 선거구
cnt = 0;
for (int i = 1; i<= x+d2; i++){
if (i>x) cnt++;
for (int j =y+cnt+1; j <= N; j++){
tmp_arr[i][j] = 2;
}
}
// 3번 선거구
cnt = -1;
for (int i = x+d1; i<=N; i++){
if (i <= x+d1+d2) cnt++;
for (int j = 1; j <=y-d1+cnt-1; j++){
tmp_arr[i][j] = 3;
}
}
// 4번 선거구
cnt = -1;
for (int i = x+d2+1; i<=N;i++){
if (i <= x+d1+d2+1) cnt++;
for (int j = y+d2-cnt; j <= N; j++){
tmp_arr[i][j] = 4;
}
}
for (int i = 1; i<=N; i++){
for (int j = 1; j <=N; j++){
num[tmp_arr[i][j]]+= map[i][j];
}
}
for (int i = 1; i <=5; i++){
min_num = min(min_num,num[i]);
max_num = max(max_num,num[i]);
}
return max_num - min_num;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> N;
for (int i = 1; i<=N; i++){
for (int j=1 ; j<=N; j++){
cin >> map[i][j];
}
}
for (int x = 1; x < N; x++){
for (int y = 2; y < N; y++){
for (int d1 = 1; d1 <= y; d1++){
for (int d2 = 1; d2 <= N-y; d2++){
if (x+d1+d2>N || y-d1 <=0 || y+d2 >N) continue;
int diff = go(x,y,d1,d2);
ans = min(ans,diff);
}
}
}
}
cout << ans <<"\n";
return 0;
}
디버깅
- 먼저, 처음에 제출했더니 시간초과가 났습니다.
- 시간초과가 날 일이 없고, 배열크기도 잘 설정해놨는데 이유를 알 수 없었습니다.
- 선거구를 정할 때, 선거구 숫자를 넣는 배열을 지역변수로 일정범위만 5로 초기화시켜주면서 진행한것이 원인이었던 것 같습니다.
- 이를 전역변수로 변경하였습니다.
- 또 다른 실수로는, (x,y),(d1,d2)를 정하고 범위를 벗어나는 경우 시뮬레이션을 진행하지 않도록 해야하는데, 그 범위를 잘못설정하였습니다.
- 기존에 d1+d2>N인 경우 진행하지 않도록 잘못 설정하였습니다.
- x+d1+d2>N, y-d1<=0, y+d2>N 범위를 하나라도 벗어나면 진행하지 않도록 변경하였습니다.
제출결과
- 12 ms
마무리
- 범위 설정이 아주 까다로운 문제였습니다.
- 삼성역량테스트기출문제로 범위체크가 까다로운 문제나 배열 회전시키는 문제를 아주 자주 내는 것 같습니다.
- 유의해서 다시한번 풀이해봐야겠습니다.