-
백준 21609번 상어중학교(자바) - 구현, bfs / 삼성 sw 역량 기출코딩테스트 2022. 4. 29. 18:47
문제
상어 중학교의 코딩 동아리에서 게임을 만들었다. 이 게임은 크기가 N×N인 격자에서 진행되고, 초기에 격자의 모든 칸에는 블록이 하나씩 들어있고, 블록은 검은색 블록, 무지개 블록, 일반 블록이 있다. 일반 블록은 M가지 색상이 있고, 색은 M이하의 자연수로 표현한다. 검은색 블록은 -1, 무지개 블록은 0으로 표현한다. (i, j)는 격자의 i번 행, j번 열을 의미하고, |r1 - r2| + |c1 - c2| = 1을 만족하는 두 칸 (r1, c1)과 (r2, c2)를 인접한 칸이라고 한다.
블록 그룹은 연결된 블록의 집합이다. 그룹에는 일반 블록이 적어도 하나 있어야 하며, 일반 블록의 색은 모두 같아야 한다. 검은색 블록은 포함되면 안 되고, 무지개 블록은 얼마나 들어있든 상관없다. 그룹에 속한 블록의 개수는 2보다 크거나 같아야 하며, 임의의 한 블록에서 그룹에 속한 인접한 칸으로 이동해서 그룹에 속한 다른 모든 칸으로 이동할 수 있어야 한다. 블록 그룹의 기준 블록은 무지개 블록이 아닌 블록 중에서 행의 번호가 가장 작은 블록, 그러한 블록이 여러개면 열의 번호가 가장 작은 블록이다.
오늘은 이 게임에 오토 플레이 기능을 만드려고 한다. 오토 플레이는 다음과 같은 과정이 블록 그룹이 존재하는 동안 계속해서 반복되어야 한다.
- 크기가 가장 큰 블록 그룹을 찾는다. 그러한 블록 그룹이 여러 개라면 포함된 무지개 블록의 수가 가장 많은 블록 그룹, 그러한 블록도 여러개라면 기준 블록의 행이 가장 큰 것을, 그 것도 여러개이면 열이 가장 큰 것을 찾는다.
- 1에서 찾은 블록 그룹의 모든 블록을 제거한다. 블록 그룹에 포함된 블록의 수를 B라고 했을 때, B2점을 획득한다.
- 격자에 중력이 작용한다.
- 격자가 90도 반시계 방향으로 회전한다.
- 다시 격자에 중력이 작용한다.
격자에 중력이 작용하면 검은색 블록을 제외한 모든 블록이 행의 번호가 큰 칸으로 이동한다. 이동은 다른 블록이나 격자의 경계를 만나기 전까지 계속 된다.
다음은 N = 5, M = 3인 경우의 예시이다.
2 2 -1 3 1 3 3 2 0 -1 0 0 0 1 2 -1 3 1 3 2 0 3 2 2 1 여기서 찾을 수 있는 크기가 가장 큰 블록 그룹을 다음과 같이 빨간색으로 표시했다.
2 2 -1 3 1 3 3 2 0 -1 0 0 0 1 2 -1 3 1 3 2 0 3 2 2 1 블록 그룹이 제거되면 다음과 같이 변하고, 점수 82점을 획득한다.
2 2 -1 3 1 2 0 -1 1 2 -1 1 3 2 2 2 1 중력이 작용하면 다음과 같이 변한다.
-1 3 1 0 -1 2 2 1 2 -1 1 3 2 2 2 2 1 90도 반시계방향으로 회전한 결과는 다음과 같다.
1 -1 2 2 1 3 0 1 3 2 -1 2 1 2 2 2 -1 다시 여기서 중력이 작용하면 다음과 같이 변한다.
1 -1 3 2 2 1 -1 1 3 2 2 1 2 0 2 -1 2 오토 플레이가 모두 끝났을 때 획득한 점수의 합을 구해보자.
입력
첫째 줄에 격자 한 변의 크기 N, 색상의 개수 M이 주어진다.
둘째 줄부터 N개의 줄에 격자의 칸에 들어있는 블록의 정보가 1번 행부터 N번 행까지 순서대로 주어진다. 각 행에 대한 정보는 1열부터 N열까지 순서대로 주어진다. 입력으로 주어지는 칸의 정보는 -1, 0, M이하의 자연수로만 이루어져 있다.
출력
첫째 줄에 획득한 점수의 합을 출력한다.
제한
- 1 ≤ N ≤ 20
- 1 ≤ M ≤ 5
예제 입력 1 복사
5 3 2 2 -1 3 1 3 3 2 0 -1 0 0 0 1 2 -1 3 1 3 2 0 3 2 2 1
예제 출력 1 복사
77
예제 입력 2 복사
6 4 2 3 1 0 -1 2 2 -1 4 1 3 3 3 0 4 2 2 1 -1 4 -1 2 3 4 3 -1 4 2 0 3 1 2 2 2 2 1
예제 출력 2 복사
125
예제 입력 3 복사
4 3 1 1 1 3 3 2 3 3 1 2 -1 3 -1 -1 1 1
예제 출력 3 복사
33
주의!! 무지개 블록은 bfs에서 visited 방문체크를 조심해야 한다.
무지개 블록은 여러 그룹에 동시에 속하는게 가능하다!
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; public class Main { static class Group implements Comparable<Group> { int x; int y; int rainbowCnt; int totalCnt; Group (int x, int y, int rainbowCnt, int totalCnt) { this.x = x; this.y = y; this.rainbowCnt = rainbowCnt; this.totalCnt = totalCnt; } @Override public int compareTo(Group group) { if (this.totalCnt == group.totalCnt) { if (this.rainbowCnt == group.rainbowCnt) { if (this.x == group.x) { return group.y - this.y; } return group.x - this.x; } return group.rainbowCnt - this.rainbowCnt; } return group.totalCnt - this.totalCnt; } } static int n; static boolean visited[][]; static int[][] map; static int[] dx = {-1,1,0,0}; static int[] dy = {0,0,-1,1}; static List<Group> list; static int answer = 0; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); n = Integer.parseInt(st.nextToken()); int 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()); } } while (true) { if (!findGroup()) break; gravity(); rotation(); gravity(); } System.out.println(answer); } static boolean findGroup() { list = new ArrayList<>(); visited = new boolean[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (!visited[i][j] && map[i][j] > 0) { bfs(i, j, true); } } } visited = new boolean[n][n]; if (list.isEmpty()) return false; else { Collections.sort(list); bfs(list.get(0).x, list.get(0).y, false); removeBlock(); } return true; } static void removeBlock() { int count = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (visited[i][j] == true) { count++; map[i][j] = -2; } } } answer += (int)Math.pow(count, 2); } static void bfs(int x, int y, boolean flag) { int rainbow = 0; int total = 1; visited[x][y] = true; Queue<int[]> queue = new LinkedList<>(); queue.offer(new int[]{x, y}); while (!queue.isEmpty()) { int[] now = queue.poll(); for (int i = 0; i < 4; i++) { int nx = now[0] + dx[i]; int ny = now[1] + dy[i]; if (nx < 0 || ny < 0 || nx >= n || ny >= n || visited[nx][ny]) continue; if (map[nx][ny] == map[x][y] || map[nx][ny] == 0) { visited[nx][ny] = true; queue.offer(new int[]{nx, ny}); if (map[nx][ny] == 0) rainbow++; total+=1; } } } if (total >= 2) list.add(new Group(x, y, rainbow, total)); if (flag) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (map[i][j] == 0) visited[i][j] = false; } } } } public static void gravity() { for (int i = n-1; i >= 0; i--) { for (int j = 0; j < n; j++) { if (map[i][j] >= 0) { int nx = i; while (true) { nx += 1; if (nx >= n || map[nx][j] != -2) break; } nx--; if (nx != i) { map[nx][j] = map[i][j]; map[i][j] = -2; } } } } } public static void rotation() { int[][] tmp = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { tmp[n-j-1][i] = map[i][j]; } } map = tmp; } }
'코딩테스트' 카테고리의 다른 글
프로그래머스 단어변환(자바) - dfs (0) 2022.05.25 프로그래머스 타겟 넘버(자바) - dfs (0) 2022.05.25 백준 21608번 상어초등학교(자바) - 구현*** (0) 2022.04.26 백준 14889번 스타트와 링크(자바) - dfs (0) 2022.04.25 백준 14888번 연산자 끼워넣기(자바) - dfs, 삼성 sw 역량 기출 (0) 2022.04.22