백준 21610 마법사 상어와 비바라기 (Java,자바)

jonghyukLee·2021년 11월 26일
1

이번에 풀어본 문제는
백준 21610번 마법사 상어와 비바라기 입니다.

📕 문제 링크

❗️코드

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

class Cloud
{
    int x,y;

    public Cloud(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

}
public class Main {
    static int answer;
    static int N,M;
    static int [][] map;
    static Cloud [] command;
    static boolean [][] visited;
    static Queue<Cloud> q;
    static int [] dx = {0,-1,-1,-1,0,1,1,1};
    static int [] dy = {-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());

        command = new Cloud[M];
        map = new int[N+1][N+1];
        visited = new boolean[N+1][N+1];

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

        for(int i = 0; i < M; ++i)
        {
            st = new StringTokenizer(br.readLine());
            command[i] = new Cloud(Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken()));
        }

        q = new LinkedList<>();
        q.add(new Cloud(N,1));
        q.add(new Cloud(N,2));
        q.add(new Cloud(N-1,1));
        q.add(new Cloud(N-1,2));

        for(int i = 0; i < M; ++i)
        {
            int dir = command[i].x - 1;
            int dist = command[i].y;

            answer = 0;
            move(dir,dist);
        }
        System.out.print(answer);
    }
    static void move(int dir, int dist)
    {
        //move
        Queue<Cloud> mvd = new LinkedList<>();
        while(!q.isEmpty())
        {
            Cloud cur = q.poll();

            int mx = cur.x + (dx[dir] * dist);
            int my = cur.y + (dy[dir] * dist);

            while(!isValid(mx)) mx = change(mx);
            while(!isValid(my)) my = change(my);

            mvd.add(new Cloud(mx,my));
            map[mx][my]++;
            visited[mx][my] = true;
        }

        //copy
        while(!mvd.isEmpty())
        {
            Cloud cur = mvd.poll();

            int cnt = 0;
            for(int idx = 1; idx <= 7; idx += 2)
            {
                int mx = cur.x + dx[idx];
                int my = cur.y + dy[idx];

                if(!isValid(mx) || !isValid(my) || map[mx][my] < 1) continue;
                cnt++;
            }
            map[cur.x][cur.y] += cnt;
        }
        make();
    }
    static void make()
    {
        for(int i = 1; i <= N; ++i)
        {
            for(int j = 1; j <= N; ++j)
            {
                if((map[i][j] >= 2) && !visited[i][j])
                {
                    q.add(new Cloud(i,j));
                    map[i][j] -= 2;
                }
                else visited[i][j] = false;
                answer += map[i][j];
            }
        }
    }
    static boolean isValid(int x)
    {
        return x > 0 && x <= N;
    }
    static int change(int x)
    {
        return x < 1 ? x + N : x - N;
    }
}

📝 풀이

구름이 M번 이동한 후 남아있는 물의 양의 합을 구하는 문제입니다.
초기 구름의 위치는 N에 따라 고정된 위치에 존재하며, 구름의 이동으로 반복이 시작됩니다.
먼저 입력으로 주어지는 방향, 거리에 맞게 구름이 이동합니다.
구름의 이동이 완료되면, 머무른 위치의 물의 값을 1 증가시킨 후 소멸합니다.
구름이 소멸한 위치를 기준으로 대각선 바구니들 중 물의 양이 1 이상인 바구니가 존재한다면, 그 개수만큼 물의 양을 더해줍니다.
마지막으로 물의 양이 2 이상인 위치에서 구름이 다시 생성되고, 2를 감소시켜주면 됩니다.

구름의 위치를 담아두기 위한 큐를 생성했고, 큐에서 값을 순차적으로 꺼내며 이동을 수행해줍니다. 이동할 위치를 조건에 맞게 선정했다면, 해당 위치의 값을 1 증가시켜주고 방문처리를 합니다.
이어서 mvd큐에 값을 다시 넣어준 이유는 대각선 값을 체크하여 물의 양을 증가시키기 위함입니다. mvd큐에서는 대각선 값들을 체크하여 값이 1 이상이라면 카운트를 증가시키고, 반복문이 끝나면 좌표값에 카운트값을 더해줍니다.

make함수에서는 맵을 탐색하며 값이 2 이상이면서, 방문하지 않은, 즉 문제의 조건에서 이전에 소멸한 구름의 위치에서는 생성될수 없다는 조건을 충족시키는 좌표에서만 구름을 생성해줍니다. 구름의 생성과 동시에 다음 반복을 위해 큐에 좌표값을 담아주고, 모든 방문배열값을 false로 다시 되돌려줍니다.
위 과정이 마지막 과정이므로 출력값을 구하기 위해 배열을 탐색하는 동시에 answer값도 누적해서 더해주었습니다.
M번의 반복이 끝난 후 answer을 출력해주면 바로 해결할 수 있습니다.

📜 후기

뭔가 복잡할것 같은 문제 소재였지만 어렵지 않았던 문제입니다.
잘 읽어보면 가볍게 풀고 넘어갈 수 있을 것 같아요!

profile
머무르지 않기!

0개의 댓글