🧫 문제 분석
✔️ 출처
📖 문제


모든 칸을 격자로 나누고 90도 회전 후
인접한 얼음이 있는 칸이 3개 미만이면 얼음의 양이 - 1로 줄어든다 (이는 동시다발로 일어난다.)
격자 나누는걸 좀 복잡하게 구현했더니 좀 느리긴한데(700ms)
회전하는 로직만 바꾸면 충분히 빠르게 될거라고 생각된다.
찾아보니 2차원 배열 회전 공식이 있어 공부했다.
참조: https://taaewoo.tistory.com/10
🔅 문제 풀이
import java.beans.Customizer;
import java.io.*;
import java.util.*;
public class Main {
static int N, Q, size;
static int[][] map;
static boolean[][] visited;
static int[] L;
static int[] dr = {0, 1, 0, -1};
static int[] dc = {-1, 0, 1, 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());
Q = Integer.parseInt(st.nextToken());
Queue<int[]> q = new LinkedList<>();
size = (int) Math.pow(2, N);
map = new int[size][size];
for (int i = 0; i < size; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < size; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
L = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
// Q번 파이어스톰 시전
for (int i = 0; i < Q; i++) {
// 2^L * 2^L 크기의 격자를 나눔
int dist = (int) Math.pow(2, L[i]);
for (int r = 0; r < size; r += dist) {
for (int c = 0; c < size; c += dist) {
rotate(dist, r, c);
}
}
for (int j = 0; j < size; j++) {
for (int k = 0; k < size; k++) {
if (map[j][k] == 0) continue;
// 인접한 얼음이 있는칸 3개 미만이면 얼음 탐색
// 인접한 칸은 상하좌우
int cnt = 0;
for (int dir = 0; dir < 4; dir++) {
int nr = j + dr[dir];
int nc = k + dc[dir];
if (!isBoundary(nr, nc)) cnt++;
}
if (cnt < 3) {
q.add(new int[]{j, k});
}
}
}
// 인접한 얼음이 있는칸 3개 미만이면 얼음 양 -1
while (!q.isEmpty()) {
int[] cur = q.poll();
map[cur[0]][cur[1]]--;
}
}
int sum = 0; // 총 합
visited = new boolean[size][size]; // 덩어리 방문 처리 용
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (map[i][j] != 0) {
sum += map[i][j];
if (!visited[i][j]) {
bfs(i,j);
}
}
}
}
// 남아있는 얼음 A[r][c]의 합
// 남아있는 얼음 중 가장 큰 덩어리가 차지하는 칸의 개수 (얼음 있고 인접해있다면 연결됨, 해당 집합을 덩어리라 함)
System.out.println(sum);
System.out.println(maxBlockSize);
}
static int maxBlockSize = 0;
private static void bfs(int r, int c) {
Queue<int[]> q = new LinkedList<>();
q.add(new int[]{r, c});
visited[r][c] = true;
int cnt = 1;
while (!q.isEmpty()) {
int[] cur = q.poll();
for (int i = 0; i < 4; i++) {
int nr = cur[0] + dr[i];
int nc = cur[1] + dc[i];
if (nr >= size || nr < 0
|| nc >= size || nc < 0
|| visited[nr][nc]
|| map[nr][nc] == 0) continue;
visited[nr][nc] = true;
q.add(new int[]{nr, nc});
cnt++;
}
}
maxBlockSize = Math.max(maxBlockSize, cnt);
}
private static void rotate(int dist, int r, int c) {
if (dist <= 0) {
return;
}
int endC = c + dist - 1;
int endR = r + dist - 1;
// 윗줄 복사
int[] tmp = new int[dist];
for (int col = c, idx = 0; col <= endC; col++, idx++) {
tmp[idx] = map[r][col];
}
// 왼쪽을 위로
for (int i = r, col = endC; i <= endR; i++, col--) {
map[r][col] = map[i][c];
}
// 아래를 왼쪽으로
for (int i = r, col = c; i <= endR; i++, col++) {
map[i][c] = map[endR][col];
}
// 오른쪽을 아래로
for (int i = endR, col = c; i >= r; i--, col++) {
map[endR][col] = map[i][endC];
}
// 위를 오른쪽으로
for (int i = endR, idx = dist - 1; i >= r; i--, idx--) {
map[i][endC] = tmp[idx];
}
// 다음 안쪽 사각형
rotate(dist - 2, r + 1, c + 1);
}
private static boolean isBoundary(int nr, int nc) {
return nr >= size || nr < 0 || nc >= size || nc < 0 || map[nr][nc] == 0;
}
}
❗ 오답노트 / 필요한 지식
'baekjoon > Implementation' 카테고리의 다른 글
백준 21609번 : 상어 중학교 [자바] (3) | 2025.08.15 |
---|---|
백준 21608번 : 상어 초등학교 [자바] (2) | 2025.08.14 |
백준 20056번 : 마법사 상어와 파이어볼 [자바] (1) | 2025.08.11 |
백준 20061번 : 모노미노도미노 2 [자바] (5) | 2025.08.06 |
백준 17822번 : 원판 돌리기 [자바] (2) | 2025.08.04 |