[백준] 20056번: 마법사 상어와 파이어볼 (JAVA)

🔗 문제 링크

20056번: 마법사 상어와 파이어볼


풀이

1) 이동

  1. 모든 파이어볼이 방향 d로 속력s만큼 이동
    • 이동하는중 같은 칸에 여러 개의 파이어볼이 존재 할 수 있어 ArrayList[][] 을 사용했다.
  2. 이동 중 배열의 범위를 벗어나면 끝이 아니라 ex) N =3 (3, 3) 좌하단으로 이동 시 -> (0, 0) 와 같이 이동
    • 범위를 벗어나가면 0 으로 치환 또는 N-1값으로 치환해주었다.

2) 합체 후 분열

  1. 같은 칸에 있는 파이어볼은 모두 하나로 합쳐진다.
    • 리스트를 돌면서 2개 이상인 경우 합체 후 분열
      • 질량 = 합쳐진 파이어볼의 질량의 합 / 5
      • 속력 = 합쳐진 파이어볼의 속력의 합 / 합쳐진 파이어볼의 개수
    • 방향 = 합쳐진 파이어볼의 방향이 모두 홀수 또는 짝수이면 방향은 0,2,4,6, 아닐 시 1,3,5,7
  2. 4개로 나누어진 파이어볼은 이동하지 않고 원래 있던 좌표에 추가

💡 고찰

처음에는 파이어볼이 합쳐진 후에 4개로 나누어질 때 합쳐진 좌표에서 다음 이동때까지 대기해야 하는데 아무 생각없이 당연히 나누어진 방향으로 이동하는걸로 혼자 착각했다.

테케는 다 맞았는데 제출하자마자 틀려서 계속 고민하다 이동 로직에서 속력에 mod 연산한 값이 그대로 객체로 저장되서 분열에 속력 구하는 부분이 이상하게 동작했다. 질문 게시판에 나와 같은 사람이 있어서 참고해 임시 변수 하나 추가해서 해결했다. 질문 게시판이 없었으면 혼자 몇시간이나 끙끙거리다 포기할뻔,,


💻 소스코드


import java.io.*;
import java.util.*;

public class Main_bj_20056_마법사상어와파이어볼 {

    static int N, M, K;
    static ArrayList<FireBall> list[][];
    static ArrayList<FireBall> tmpList[][];
    static int di[] = {-1, -1, 0, 1, 1, 1, 0, -1};
    static int dj[] = {0, 1, 1, 1, 0, -1, -1, -1};

    public static void main(String[] args) throws Exception {

        System.setIn(new FileInputStream("res/input.txt"));
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());

        // 어레이 리스트 배열에 파이어볼 정보 저장
        list = new ArrayList[N][N];
        tmpList = new ArrayList[N][N];

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                list[i][j] = new ArrayList<FireBall>();
                tmpList[i][j] = new ArrayList<FireBall>();
            }
        }

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine(), " ");
            int r = Integer.parseInt(st.nextToken()) - 1;
            int c = Integer.parseInt(st.nextToken()) - 1;
            int m = Integer.parseInt(st.nextToken()); // 질량
            int s = Integer.parseInt(st.nextToken()); // 속력
            int d = Integer.parseInt(st.nextToken()); // 방향
            list[r][c].add(new FireBall(m, s, d));
        }

        // K 만큼 로직 수행
        for (int k = 0; k < K; k++) {
            // 이동
            move();
            // 분산
            spread();

            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    list[i][j].clear();
                    for (int n = 0; n < tmpList[i][j].size(); n++) {
                        list[i][j].add(tmpList[i][j].get(n));
                    }
                    tmpList[i][j].clear();
                }
            }
        }

        int sum = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                for (int k = 0; k < list[i][j].size(); k++) {
                    sum = sum + list[i][j].get(k).m;
                }
            }
        }
        System.out.print(sum);
    }

    static void move() {

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                for (int n = 0; n < list[i][j].size(); n++) {
                    int m = list[i][j].get(n).m;
                    int s = list[i][j].get(n).s;
                    int d = list[i][j].get(n).d;

                    int tmpS = s % N;
                    int r = i;
                    int c = j;
                    for (int k = 0; k < tmpS; k++) {
                        r = r + di[d];
                        c = c + dj[d];
                        if (r == -1) {
                            r = N - 1;
                        } else if (r == N) {
                            r = 0;
                        }

                        if (c == -1) {
                            c = N - 1;
                        } else if (c == N) {
                            c = 0;
                        }
                    }
                    tmpList[r][c].add(new FireBall(m, s, d));
                }
            }
        }
    }

    static void spread() {

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                int size = tmpList[i][j].size();
                if (size >= 2) {
                    int sumM = 0;
                    int sumS = 0;
                    int flag = 0; // 방향이 짝수이면 1증가
                    for (int k = 0; k < tmpList[i][j].size(); k++) {
                        FireBall fb = tmpList[i][j].get(k);
                        sumM = sumM + fb.m;
                        sumS = sumS + fb.s;
                        if (fb.d % 2 == 0) flag = flag + 1;
                    }
                    tmpList[i][j].clear();

                    if (sumM / 5 != 0) {
                        if (flag == 0 || flag == size) {
                            for (int k = 0; k <= 6; k += 2) {
                                tmpList[i][j].add(new FireBall(sumM / 5, sumS / size, k));
                            }
                        } else {
                            for (int k = 1; k <= 7; k += 2) {
                                tmpList[i][j].add(new FireBall(sumM / 5, sumS / size, k));
                            }
                        }
                    }
                }
            }
        }
    }

    static class FireBall {
        int m, s, d; // 질량m 속력s 방향d

        FireBall(int m, int s, int d) {
            this.m = m;
            this.s = s;
            this.d = d;
        }
    }
}

Categories:

Updated:

Leave a comment