본문 바로가기
Coding Test

[백준] 20058 마법사 상어와 파이어스톰 - 자바

by 쌩욱 2022. 4. 9.

 

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

 

20058번: 마법사 상어와 파이어스톰

마법사 상어는 파이어볼과 토네이도를 조합해 파이어스톰을 시전할 수 있다. 오늘은 파이어스톰을 크기가 2N × 2N인 격자로 나누어진 얼음판에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c

www.acmicpc.net

 

👀 풀이

배열 회전과 BFS를 사용해서 풀이했습니다.

 

파이어스톰 시전 시

1. 2^L * 2^L 크기의 격자들로 나눈 후 시계방향 90도 회전

2. 인접한 얼음 확인 후 얼음 3개 미만 시 얼음-1

 

파이어스톰 다 끝난 후

3. 남아있는 얼음 합 구하기

4. 가장 큰 덩어리 크기 구하기 (BFS)

 

[배열 회전 함수]

    public static void rotate() {
        for (int i = 0; i < N; i += L) {
            for (int j = 0; j < N; j += L) {
                rotatePart(i, j);
            }
        }
    }

    public static void rotatePart(int r, int c) {
        int[][] tmp = new int[L][L];
        for (int i = 0; i < L; i++) {
            for (int j = 0; j < L; j++) {
                tmp[i][j] = map[r+L-1-j][c+i];
            }
        }

        for (int i = 0; i < L; i++) {
            for (int j = 0; j < L; j++) {
                map[r+i][c+j] = tmp[i][j];
            }
        }
    }

L 은 2^L로 미리 계산하였고 격자 크기만큼 인덱스를 넘어가며 회전을 시켰습니다.

시계방향 90도 회전이기 때문에 새로운 배열의 행은 기존 배열의 열과 매치시켰습니다.

 

[인접 얼음 확인 함수]

public static void reduceIce(){
        int[][] tmp = deepCopy(map);
        for(int i=0; i<N; i++){
            for(int j=0; j<N; j++){
                if(tmp[i][j] == 0) continue;

                int cnt = 0;
                for(int k=0; k<4; k++){
                    int nr = i + dr[k];
                    int nc = j + dc[k];
                    if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
                    if(map[nr][nc] > 0) cnt++;
                }

                if(cnt < 3){
                    tmp[i][j]--;
                }
            }
        }
        map = tmp;
}

새로운 배열을 복사하고 위, 아래, 왼쪽, 오른쪽을 순회하며 얼음 숫자를 세고 3미만일 시 얼음을 감소시켰습니다.

 

👀 전체 코드

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

public class BOJ_20058_파이어스톰 {
    static int N, Q, L;
    static int[][] map;
    static int[] level;
    static int[] dr = {-1, 1, 0, 0};
    static int[] dc = {0, 0, -1, 1};
    static int sum, cell;
    static boolean[][] visited;

    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());
        level = new int[Q];
        N = (int) Math.pow(2, N);

        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());
            }
        }

        st = new StringTokenizer(br.readLine());
        for (int i = 0; i < Q; i++) {
            level[i] = Integer.parseInt(st.nextToken());
        }

        for (int q = 0; q < Q; q++) {
            L = (int) Math.pow(2, level[q]);
            rotate(); // L 간격으로 90도 시계방향 회전
            reduceIce();// 인접 확인, 얼음 줄이기
        }

        // 남은 얼음 합 구하기
        // 가장 큰 덩어리 칸 개수 구하기
        visited = new boolean[N][N];
        for(int i=0; i<N; i++){
            for(int j=0; j<N; j++){
                sum += map[i][j];
                if(!visited[i][j] && map[i][j] > 0){
                    cell = Math.max(cell, bfs(i, j));
                }
            }
        }

        System.out.println(sum);
        System.out.println(cell);
    }

    public static int bfs(int i, int j){
        Queue<int[]> q = new LinkedList<>();
        q.add(new int[]{i, j});
        visited[i][j] = true;
        int count = 1;

        while (!q.isEmpty()) {
            int[] poll = q.poll();
            int r = poll[0];
            int c = poll[1];

            for(int k=0; k<4; k++){
                int nr = r + dr[k];
                int nc = c + dc[k];
                if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
                if(!visited[nr][nc] && map[nr][nc] > 0){
                    count++;
                    visited[nr][nc] = true;
                    q.add(new int[]{nr, nc});
                }
            }
        }
        return count;
    }

    public static void reduceIce(){
        int[][] tmp = deepCopy(map);
        for(int i=0; i<N; i++){
            for(int j=0; j<N; j++){
                if(tmp[i][j] == 0) continue;

                int cnt = 0;
                for(int k=0; k<4; k++){
                    int nr = i + dr[k];
                    int nc = j + dc[k];
                    if(nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
                    if(map[nr][nc] > 0) cnt++;
                }

                if(cnt < 3){
                    tmp[i][j]--;
                }
            }
        }
        map = tmp;
    }

    public static void rotate() {
        for (int i = 0; i < N; i += L) {
            for (int j = 0; j < N; j += L) {
                // i ~ i+L-1 , j ~ j+L-1 회전하기
                rotatePart(i, j);
            }
        }
    }

    public static void rotatePart(int r, int c) {
        int[][] tmp = new int[L][L];
        for (int i = 0; i < L; i++) {
            for (int j = 0; j < L; j++) {
                tmp[i][j] = map[r+L-1-j][c+i];
            }
        }

        for (int i = 0; i < L; i++) {
            for (int j = 0; j < L; j++) {
                map[r+i][c+j] = tmp[i][j];
            }
        }
    }

    public static int[][] deepCopy(int[][] map) {
        int[][] tmp = new int[map.length][map.length];
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map.length; j++) {
                tmp[i][j] = map[i][j];
            }
        }
        return tmp;
    }

    public static void print(int[][] arr){
        int len = arr.length;
        for(int i=0; i<len; i++){
            for(int j=0; j<len; j++){
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}