게리맨더링2


백준 [17779] 게리맨더링2

문제보기
Alt text

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int N, ans;
	static int[][] map;

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		N = Integer.parseInt(br.readLine());
		map = new int[N + 1][N + 1];
		ans = 987654321;

		for (int i = 1; i < N + 1; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			for (int j = 1; j < N + 1; j++) {
				map[i][j] = Integer.parseInt(st.nextToken());
			}
		}

		seperate();
		System.out.println(ans);
	}

	public static void seperate() {
		for (int i = 1; i < N; i++) { // d1
			for (int j = 1; j < N; j++) { // d2
				standard(i, j);
			}
		}
	}

	public static void standard(int d1, int d2) {
		for (int x = 1; x < N; x++) { // x
			for (int y = 1; y < N; y++) { // y
				boolean flag = false;
				int max = 0;
				int min = 987654321;
				boolean[][] chk = new boolean[N + 1][N + 1];

				if ((x >= x + d1 + d2) || (x + d1 + d2 > N) || (y - d1 < 1) || (y - d1 >= y) || (y >= y + d2)
						|| (y + d2 > N)) {
					flag = true;
					continue;
				} else {
					// 1번 선거구
					out: if (!flag) {
						int sum = 0;
						int idx = 0;
						for (int i = 1; i < x + d1; i++) {
							jump: for (int j = 1; j <= y; j++) {
								if (!isRange(i, j)) {
									flag = true;
									break out;
								}
								if (i >= x && j >= y - idx) { // 경계선
									idx++;
									break jump;
								}
								chk[i][j] = true;
								sum += map[i][j];
							}
						}
						if (sum == 0)
							flag = true;
						else {
							max = Math.max(max, sum);
							min = Math.min(min, sum);
						}
					}
					// 2번 선거구
					out: if (!flag) {
						int sum = 0;
						int idx = 0;
						for (int i = 1; i <= x + d2; i++) {
							jump: for (int j = N; j > y; j--) {
								if (!isRange(i, j)) {
									flag = true;
									break out;
								}
								if (i > x && j <= y + 1 + idx) { // 경계선
									idx++;
									break jump;
								}
								chk[i][j] = true;
								sum += map[i][j];
							}
						}
						if (sum == 0)
							flag = true;
						else {
							max = Math.max(max, sum);
							min = Math.min(min, sum);
						}
					}

					// 3번 선거구
					out: if (!flag) {
						int sum = 0;
						int idx = 0;
						for (int i = x + d1; i <= N; i++) {
							jump: for (int j = 1; j < y - d1 + d2; j++) {
								if (!isRange(i, j)) {
									flag = true;
									break out;
								}
								if (i >= x + d1 && j >= y - d1 + idx) {
									idx++;
									break jump;
								}
								chk[i][j] = true;
								sum += map[i][j];
							}
						}
						if (sum == 0)
							flag = true;
						else {
							max = Math.max(max, sum);
							min = Math.min(min, sum);
						}
					}
					// 4번 선거구
					out: if (!flag) {
						int sum = 0;
						int idx = 0;
						for (int i = x + d2 + 1; i <= N; i++) {
							jump: for (int j = N; j >= y - d1 + d2; j--) {
								if (!isRange(i, j)) {
									flag = true;
									break out;
								}
								if (i > x + d2 && j < y + d2 - idx) {
									idx++;
									break jump;
								}
								chk[i][j] = true;
								sum += map[i][j];
							}
						}
						if (sum == 0)
							flag = true;
						else {
							max = Math.max(max, sum);
							min = Math.min(min, sum);
						}
					}
					// 5번 선거구
					if (!flag) {
						int sum = 0;
						for (int i = x; i <= x + d1 + d2; i++) {
							for (int j = y - d1; j <= y + d2; j++) {
								if (!chk[i][j]) {
									sum += map[i][j];
								}
							}
						}
						if (sum == 0)
							flag = true;
						else {
							max = Math.max(max, sum);
							min = Math.min(min, sum);
						}
					}
				}
				if (!flag) {
					int diff = Math.abs(min - max);
					ans = Math.min(diff, ans);
				}
			}
		}
	}

	public static boolean isRange(int r, int c) {
		return r >= 1 && c >= 1 && r <= N && c <= N;
	}
}