알고리즘/구현

자바 | 백준 | 21609 | 상어 중학교

cha-n 2021. 10. 24. 20:56

Solution

import java.io.*;
import java.util.*;

public class Main {

	static int N, M;
	static int[][] map;
	static boolean[][] visited;
	static int[] dx = { -1, 1, 0, 0 };
	static int[] dy = { 0, 0, -1, 1 };
	static List<int[]> blockGroup, biggestBlockGroup;

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());

		map = new int[N][N];

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

			}
		}

		int score = 0;
		while (findBiggestBlockGroup()) {
			score += removeBlockGroup(biggestBlockGroup);
			down();
			rotate();
			down();
		}

		System.out.println(score);
	}

	static void rotate() {
		int[][] rotateMap = new int[N][N];

		for (int j = N - 1; j >= 0; j--) {
			for (int i = 0; i < N; i++) {
				rotateMap[N - j - 1][i] = map[i][j];
			}
		}

		for (int i = 0; i < N; i++) {
			map[i] = rotateMap[i].clone();
		}
	}

	static void down() {
		for (int j = 0; j < N; j++) {
			int emptyCnt = 0;
			int blockCnt = 0;
			List<Integer> blocks = new ArrayList<>();
			int i = N - 1;
			for (; i >= 0; i--) {
				if (map[i][j] == -2) { // 빈 칸
					emptyCnt++;
					// blockCnt = 0;
				} else if (map[i][j] == -1) { // -1은 중력 영향 X
					if (emptyCnt != 0) {
						for (; blockCnt > 0; blockCnt--) {
							map[i + blockCnt + emptyCnt][j] = blocks.get(blocks.size() - blockCnt);
						}

						for (; emptyCnt > 0; emptyCnt--) {
							map[i + emptyCnt][j] = -2;
						}
					}
					blockCnt = 0;
					emptyCnt = 0;
					blocks.clear();
				} else {
					blocks.add(map[i][j]);
					blockCnt++;
				}
			}

			if (emptyCnt != 0) { // 빈 칸이 있으면
				for (; blockCnt > 0; blockCnt--) {
					map[i + blockCnt + emptyCnt][j] = blocks.get(blocks.size() - blockCnt);
					map[i + blockCnt][j] = -2;
				}

				for (; emptyCnt > 0; emptyCnt--) {
					map[i + emptyCnt][j] = -2;
				}
			}

		}
	}

	static int removeBlockGroup(List<int[]> group) {
		for (int[] point : group) {
			map[point[0]][point[1]] = -2; // 빈 칸
		}
		return group.size() * group.size();
	}

	static boolean findBiggestBlockGroup() {
		biggestBlockGroup = new ArrayList<>();
		visited = new boolean[N][N];

		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (map[i][j] >= 1 && map[i][j] <= M && !visited[i][j]) {
					blockGroup = new ArrayList<>();

					dfs(i, j, map[i][j]);

					if (biggestBlockGroup.size() < blockGroup.size()) {
						biggestBlockGroup = blockGroup;
					} else if (biggestBlockGroup.size() == blockGroup.size()) {
						if (compareBlockGroup(biggestBlockGroup, blockGroup) == 2) {
							biggestBlockGroup = blockGroup;
						}
					}
					initVisited();
				}
			}
		}

		if (biggestBlockGroup.size() != 0 && biggestBlockGroup.size() != 1) {
			return true;
		} else {
			return false;
		}
	}

	static int compareBlockGroup(List<int[]> group1, List<int[]> group2) {
		int[] standard1 = getStandard(group1);
		int[] standard2 = getStandard(group2);

		if (standard1[0] != standard2[0]) {
			if (standard1[0] > standard2[0]) {
				return 1;
			} else {
				return 2;
			}
		} else {
			if (standard1[1] != standard2[1]) {
				if (standard1[1] > standard2[1]) {
					return 1;
				} else {
					return 2;
				}
			} else {
				if (standard1[2] > standard2[2]) {
					return 1;
				} else {
					return 2;
				}
			}
		}
	}

	static int[] getStandard(List<int[]> group) {
		int rainbowBlockCnt = 0;
		int row = Integer.MAX_VALUE;
		int col = Integer.MAX_VALUE;

		for (int[] point : group) {
			if (map[point[0]][point[1]] == 0) {
				rainbowBlockCnt++;
			} else {
				if (row > point[0]) {
					row = point[0];
					col = point[1];
				} else if (row == point[0]) {
					col = Math.min(col, point[1]);
				}
			}
		}

		return new int[] { rainbowBlockCnt, row, col };
	}

	static void dfs(int x, int y, int color) {
		visited[x][y] = true;
		blockGroup.add(new int[] { x, y });

		for (int d = 0; d < 4; d++) {
			int nx = x + dx[d];
			int ny = y + dy[d];

			if (isIn(nx, ny) && (map[nx][ny] == 0 || map[nx][ny] == color) && !visited[nx][ny]) {
				dfs(nx, ny, color);
			}
		}
	}

	static void initVisited() {
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (map[i][j] == 0 || map[i][j] == -1) {
					visited[i][j] = false;
				}
			}
		}
	}

	static boolean isIn(int x, int y) {
		return 0 <= x && x < N && 0 <= y && y < N;
	}
}

 

https://www.acmicpc.net/problem/21609