백준 17779 - 게리맨더링 2
Updated:
Java
17779 번 - 게리맨더링 2
문제
- 기준점 (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
접근 방법
- 0,1 에서 부터 N-3,N-2 까지 탐색한다
- 각 점에서 d1을 1부터 범위 벗어날때까지, d2를 1부터 범위 벗어날 때 까지 탐색
- 경계를 그린다.
- 그려진 경계에 따라 선거구의 인구수를 구한다.
- 가장 많은 선거구 인구 수와 가장 적은 선거구 인구 수의 차이를 구한다.
코드
import java.util.*;
import java.io.*;
public class Main {
static int n, result = Integer.MAX_VALUE, maxH;
static int[][] map;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk;
n = stoi(br.readLine());
map = new int[n][n];
for (int i = 0; i < n; i++) {
stk = new StringTokenizer(br.readLine());
for (int j = 0; j < n; j++) {
map[i][j] = stoi(stk.nextToken());
maxH += map[i][j];
}
}
// 다이아몬드 경계선을 나눌 수 있는 시작 좌표들을 하나씩 준다
for (int i = 0; i <= n - 3; i++) {
for (int j = 1; j <= n - 2; j++) {
makeBound(i,j);
}
}
System.out.println(result);
br.close();
}
// 경계선 그을 필요 값 만들기
static void makeBound(int y, int x) {
int d1 = 1, d2 = 1;
while (x - d1 >= 0 && y + d1 + d2 < n) {
while (x + d2 < n && y + d1 + d2 < n) {
// map을 벗어나지 않는 d1과 d2를 준다.
result = Math.min(cal(y, x, d1, d2, new boolean[n][n]), result);
d2++;
}
d1++;
d2 = 1;
}
}
// 경계선 긋기
static int cal(int y, int x, int d1, int d2, boolean[][] vis) {
int diff = 0;
int[] area = new int[5];
vis[y][x] = true;
// 다이아몬드 모양으로 경계선을 그린다.
for (int i = 1; i <= d1; i++) {
vis[y + i][x - i] = true; // 1
vis[y + d2 + i][x + d2 - i] = true; // 4
}
for (int i = 1; i <= d2; i++) {
vis[y + i][x + i] = true; // 2
vis[y + d1 + i][x - d1 + i] = true; // 3
}
//--------1,2,3,4 각 구역의 인구수 합을 구한다----------
for(int i = 0; i < y + d1; i++) { // 1
for(int j = 0; j <= x; j++ ) {
if(vis[i][j])
break;
area[0] += map[i][j];
}
}
for(int i = 0; i <= y + d2; i++) { // 2
for(int j = n - 1; j > x; j-- ) {
if(vis[i][j])
break;
area[1] += map[i][j];
}
}
for(int i = y + d1; i < n; i++) { // 3
for(int j = 0; j < x - d1 + d2; j++ ) {
if(vis[i][j])
break;
area[2] += map[i][j];
}
}
for(int i = y + d2 + 1; i < n; i++) { // 4
for(int j = n - 1; j >= x - d1 + d2; j--) {
if(vis[i][j])
break;
area[3] += map[i][j];
}
}
area[4] = maxH;
// 5구역은 전체 인구수에서 1,2,3,4 구역의 인구수를 뺀 값과 같다.
for(int i = 0; i < 4; i++) {
area[4] -= area[i];
}
Arrays.sort(area);
diff = area[4] - area[0]; // 최대, 최소의 차이를 구한다.
return diff;
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
총평
난이도
⭐⭐★★★
후기
간단한 구현 문제였다.
개선할 점
없