Algorithm/문제 풀이 / / 2023. 6. 29. 01:23

[BAEKJOON_21610 - JAVA] 마법사 상어와 비바라기

반응형

문제

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

 

21610번: 마법사 상어와 비바라기

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기

www.acmicpc.net

 

JAVA코드

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

public class Main {

    private static int N, M;
    private static int[][] map;
    private static boolean[][] visited;
    // 0, 1, 2, 3, 4, 5, 6, 7, 8
    // 공백, ←, ↖, ↑, ↗, →, ↘, ↓, ↙
    private static int[] dy = { 0, 0, -1, -1, -1, 0, 1, 1, 1 };
    private static int[] dx = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };

    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());
        M = Integer.parseInt(st.nextToken());
        map = new int[N + 1][N + 1];
        visited = new boolean[N + 1][N + 1];

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

        int di = 0;
        int si = 0;
        List<Cloud> clouds = new ArrayList<>();
        // 비바라기를 시전하면 (N, 1), (N, 2), (N-1, 1), (N-1, 2)에 비구름이 생긴다.
        clouds.add(new Cloud(N, 1));
        clouds.add(new Cloud(N, 2));
        clouds.add(new Cloud(N - 1, 1));
        clouds.add(new Cloud(N - 1, 2));

        for (int idx = 1; idx <= M; idx++) {
            st = new StringTokenizer(br.readLine());
            di = Integer.parseInt(st.nextToken());
            si = Integer.parseInt(st.nextToken());

            // init cloud visited
            for (int row = 1; row <= N; row++) {
                for (int col = 1; col <= N; col++) {
                    visited[row][col] = false;
                }
            }

            for (Cloud cloud : clouds) {
                // 1. 모든 구름이 di 방향으로 si칸 이동한다.
                cloud.setRow(convertPos(((cloud.getRow() + (si * dy[di])) % N)));
                cloud.setCol(convertPos(((cloud.getCol() + (si * dx[di])) % N)));

                // 2. 각 구름에서 비가 내려 구름이 있는 칸의 바구니에 저장된 물의 양이 1 증가한다.
                map[cloud.getRow()][cloud.getCol()] += 1;

                // 3. 기존 구름의 위치 기록
                visited[cloud.getRow()][cloud.getCol()] = true;

            }

            for (Cloud cloud : clouds) {
                // 4. 2에서 물이 증가한 칸 (r, c)에 물복사버그 마법을 시전한다. 물복사버그 마법을 사용하면,
                // 대각선 방향으로 거리가 1인 칸에 물이 있는 바구니의 수만큼 (r, c)에 있는 바구니의 물이 양이 증가한다.
                for (int cross = 2; cross <= 8; cross = cross + 2) {

                    // 4-1. 이때는 이동과 다르게 경계를 넘어가는 칸은 대각선 방향으로 거리가 1인 칸이 아니다.
                    // 4-2. 예를 들어, (N, 2)에서 인접한 대각선 칸은 (N-1, 1), (N-1, 3)이고,
                    // (N, N)에서 인접한 대각선 칸은 (N-1, N-1)뿐이다.
                    if (!isValid(cloud.getRow() + dy[cross], cloud.getCol() + dx[cross]))
                        continue;

                    if (map[cloud.getRow() + dy[cross]][cloud.getCol() + dx[cross]] != 0) {
                        map[cloud.getRow()][cloud.getCol()] += 1;
                    }
                }
            }
            // 3. 구름이 모두 사라진다.
            clouds.clear();
            ;

            // 5. 바구니에 저장된 물의 양이 2 이상인 모든 칸에 구름이 생기고, 물의 양이 2 줄어든다.
            // 이때 구름이 생기는 칸은 3에서 구름이 사라진 칸이 아니어야 한다.
            for (int row = 1; row <= N; row++) {
                for (int col = 1; col <= N; col++) {
                    if ((map[row][col] >= 2) && !visited[row][col]) {
                        map[row][col] -= 2;
                        clouds.add(new Cloud(row, col));
                    }
                }
            }

            // System.out.println();
            // System.out.println("M: " + idx);
            // for (int row = 1; row <= N; row++) {
            // for (int col = 1; col <= N; col++) {
            // System.out.print(map[row][col] + " ");
            // }
            // System.out.println();
            // }
        }

        // M번의 이동이 모두 끝난 후 바구니에 들어있는 물의 양의 합을 구해보자.
        int result = 0;
        for (int row = 1; row <= N; row++) {
            for (int col = 1; col <= N; col++) {
                result += map[row][col];
            }
        }

        System.out.println(result);
        br.close();
    }

    // 격자의 가장 왼쪽 윗 칸은 (1, 1)이고, 가장 오른쪽 아랫 칸은 (N, N)이다.
    // 마법사 상어는 연습을 위해 1번 행과 N번 행을 연결했고, 1번 열과 N번 열도 연결했다.
    // 즉, N번 행의 아래에는 1번 행이, 1번 행의 위에는 N번 행이 있고,
    // 1번 열의 왼쪽에는 N번 열이, N번 열의 오른쪽에는 1번 열이 있다.
    public static int convertPos(int pos) {
        if (pos < 1)
            return (N + pos) == 0 ? N : (N + pos);
        return pos;
    }

    public static boolean isValid(int row, int col) {
        if (row < 1 || col < 1 || row > N || col > N)
            return false;
        return true;
    }

    public static class Cloud {
        int row;
        int col;

        public Cloud(int row, int col) {
            this.row = row;
            this.col = col;
        }

        public int getRow() {
            return row;
        }

        public int getCol() {
            return col;
        }

        public void setRow(int row) {
            this.row = row;
        }

        public void setCol(int col) {
            this.col = col;
        }

    }
}
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유