Java/코딩테스트

백준 19237

Bubbles 2023. 10. 12. 23:54

🦈 백준 19237 : 어른 상어

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

 

19237번: 어른 상어

첫 줄에는 N, M, k가 주어진다. (2 ≤ N ≤ 20, 2 ≤ M ≤ N2, 1 ≤ k ≤ 1,000) 그 다음 줄부터 N개의 줄에 걸쳐 격자의 모습이 주어진다. 0은 빈칸이고, 0이 아닌 수 x는 x번 상어가 들어있는 칸을 의미

www.acmicpc.net

 

🦈 생각보다 괜찮게 풀었던 문제. 마법사 상어와 복제마법 문제와 로직이 어느정도 겹치는 느낌이 있다. (냄새 배열을 3차원으로 만드는 것 등) 

 

🦈 Static 변수들

// 상 : 0, 하 : 1, 좌 : 2, 우 : 3
private static int[] dirX = { -1, 1, 0, 0 }; // 상하좌우 순
private static int[] dirY = { 0, 0, -1, 1 };
private static int[][] map;
private static int[][][] order;
private static int[][][] smell;
private static int n, m, k, sharkCount;
private static ArrayList<Pos>[] sharkPos;

* 참고로 방향 넣을 때 -1해서 넣어줘야 한다. (문제의 입력은 1부터 시작하므로)

 

🦈 메인 로직

  • makeSmell() : 냄새를 자기가 있는 칸에 남긴다. 상어 좌표정보 리스트를 돌면서, 살아있는 상어라면 해당 칸에 k만큼 냄새 남기기
private static void makeSmell() {
    for (int i = 1; i <= m; i++) {
        if (!sharkPos[i].isEmpty())
            smell[sharkPos[i].get(0).x][sharkPos[i].get(0).y][i] = k;
    }
}
  • moveShark() : 상어를 움직인다.
    • ArrayList<Pos>[] sharkPos : 상어의 위치정보  
    • int [ i ][ d ][  ] order : 각 상어의 우선순위 배열, i번째 상어가 현재 d 방향일때의 각 우선순위를 담은 3차원 배열이다.
    • 이미 죽은 상어라면 넘기고, 살아있다면 우선순위에 맞게 탐색한다.
      • 좌표가 유효한지 검사 isValid()
      • 냄새 검사 
        • smell [ x ] [ y ] [ i ] : x , y 좌표에 i번째 상어의 냄새가 있는지 여부 
        • 즉, 상어 개수만큼 마지막 i에 대해 for문 돌려줘야 한다.
      • 냄새가 없는 칸을 발견하면 해당 칸으로 이동한다. map[x][y] = 0, map[nextX][nextY] = 상어번호, sharkPos 갱신
        • 다른 상어가 있다면 번호를 비교한 후 번호가 더 큰 상어는 없애기
          • sharkPos[bigger].remove(0);
          • map 갱신 
      • 다 냄새가 있다면 findOwnSmell ( int index , Pos pos )
private static void moveShark() {
    for (int i = 1; i<=m; i++) {
        if (sharkPos[i].isEmpty() || sharkPos[i].size() == 0) {
            continue;
        }
        Pos pos = sharkPos[i].get(0);

        boolean find = false;
        int x = pos.x;
        int y = pos.y;
        int dir = pos.dir;

        for (int j = 0; j < 4; j++) {
            int nextX = x + dirX[order[i][dir][j]];
            int nextY = y + dirY[order[i][dir][j]];

            if (!isValid(nextX, nextY)) {
                continue;
            }

            int smellCount = 0;
            for (int s = 1; s <= m; s++) {
                if (smell[nextX][nextY][s] == 0) {
                    smellCount++;
                }
            }

            if (smellCount == m) { // 냄새가 없는 칸이라면
                find = true;
                // 칸에 다른 상어도 없는 경우
                if (map[nextX][nextY] == 0) {
                    sharkPos[i].set(0, new Pos(nextX, nextY, order[i][dir][j]));
                    map[nextX][nextY] = i;
                    map[pos.x][pos.y] = 0;
                } else {
                    // 다르 상어가 있다면
                    if (map[nextX][nextY] > i) { // 나보다 약한애라면
                        sharkPos[i].set(0, new Pos(nextX, nextY, order[i][dir][j]));
                        sharkPos[map[nextX][nextY]].remove(0);
                        map[nextX][nextY] = i;
                        map[pos.x][pos.y] = 0;
                    } else { // 나보다 강한애라면
                        map[pos.x][pos.y] = 0;
                        sharkCount--;
                        sharkPos[i].remove(0);
                    }
                }
                break;
            }
        }

        if (!find) {
            // 자기 냄새 있는 칸 찾기
            findOwnSmell(i, pos);
        }
    }
}
  • findOwnSmell( int index, Pos pos )
    • pos 기준, order대로 4방향 탐색을 하면된다.
    • 움직인 후 map 갱신 
private static void findOwnSmell(int index, Pos pos) {
    int dir = pos.dir;
    int x = pos.x;
    int y = pos.y;

    for (int i = 0; i < 4; i++) {
        int nextX = x + dirX[order[index][dir][i]];
        int nextY = y + dirY[order[index][dir][i]];

        if (!isValid(nextX, nextY)) {
            continue;
        }

        if (smell[nextX][nextY][index] > 0) {
            sharkPos[index].set(0, new Pos(nextX, nextY, order[index][dir][i]));
            map[x][y]= 0;
            map[nextX][nextY] = index;
            return;
        }
    }
}

 

  • removeSmell() : 냄새 제거
private static void removeSmell() {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int s = 1; s <= m; s++) {
                if (smell[i][j][s] > 0) {
                    smell[i][j][s]--;
                }
            }
        }
    }
}

 


 

 

🦈 전체 코드 

import java.util.*;
import java.io.*;
public class p19237 {
    // 상 : 0, 하 : 1, 좌 : 2, 우 : 3
    private static int[] dirX = { -1, 1, 0, 0 }; // 상하좌우 순
    private static int[] dirY = { 0, 0, -1, 1 };
    private static int[][] map;
    private static int[][][] order;
    private static int[][][] smell;
    private static int n, m, k, sharkCount;
    private static ArrayList<Pos>[] sharkPos;

    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());
        k = Integer.parseInt(st.nextToken());

        map = new int[n][n];
        order = new int[m+1][4][4];
        smell = new int[n][n][m+1];
        sharkPos = new ArrayList[m+1];
        sharkCount = m;
        int time = 0;

        for (int i = 0; i <= m; i++) {
            sharkPos[i] = new ArrayList<>();
        }

        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());
                if (map[i][j] != 0) {
                    sharkPos[map[i][j]].add(new Pos(i, j, 0));
                }
            }
        }

        // 상어들의 초기 방향
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= m; i++) {
            int dir = Integer.parseInt(st.nextToken());
            sharkPos[i].set(0, new Pos(sharkPos[i].get(0).x, sharkPos[i].get(0).y, dir-1));
        }

        for (int i = 1; i <= m; i++) {
            // i번째 상어의 우선순위 인풋
            for (int d = 0; d < 4; d++) {
                st = new StringTokenizer(br.readLine());
                for (int j = 0; j < 4; j++) {
                    // 방향 0부터 시작하므로 -1해준다.
                    order[i][d][j] = Integer.parseInt(st.nextToken()) - 1;
                }
            }
        }

        while (sharkCount > 1 && time <= 1000) {
            magic();
            time++;
        }

        if (time > 1000) {
            System.out.println(-1);
        } else {
            System.out.println(time);
        }

    }

    private static void magic() {
         makeSmell();
         moveShark();
         removeSmell();
    }

    private static void moveShark() {
        for (int i = 1; i<=m; i++) {
            if (sharkPos[i].isEmpty() || sharkPos[i].size() == 0) {
                continue;
            }
            Pos pos = sharkPos[i].get(0);

            boolean find = false;
            int x = pos.x;
            int y = pos.y;
            int dir = pos.dir;

            for (int j = 0; j < 4; j++) {
                int nextX = x + dirX[order[i][dir][j]];
                int nextY = y + dirY[order[i][dir][j]];

                if (!isValid(nextX, nextY)) {
                    continue;
                }

                int smellCount = 0;
                for (int s = 1; s <= m; s++) {
                    if (smell[nextX][nextY][s] == 0) {
                        smellCount++;
                    }
                }

                if (smellCount == m) { // 냄새가 없는 칸이라면
                    find = true;
                    // 칸에 다른 상어도 없는 경우
                    if (map[nextX][nextY] == 0) {
                        sharkPos[i].set(0, new Pos(nextX, nextY, order[i][dir][j]));
                        map[nextX][nextY] = i;
                        map[pos.x][pos.y] = 0;
                    } else {
                        // 다르 상어가 있다면
                        if (map[nextX][nextY] > i) { // 나보다 약한애라면
                            sharkPos[i].set(0, new Pos(nextX, nextY, order[i][dir][j]));
                            sharkPos[map[nextX][nextY]].remove(0);
                            map[nextX][nextY] = i;
                            map[pos.x][pos.y] = 0;
                        } else { // 나보다 강한애라면
                            map[pos.x][pos.y] = 0;
                            sharkCount--;
                            sharkPos[i].remove(0);
                        }
                    }
                    break;
                }
            }

            if (!find) {
                // 자기 냄새 있는 칸 찾기
                findOwnSmell(i, pos);
            }
        }
    }

    private static void findOwnSmell(int index, Pos pos) {
        int dir = pos.dir;
        int x = pos.x;
        int y = pos.y;

        for (int i = 0; i < 4; i++) {
            int nextX = x + dirX[order[index][dir][i]];
            int nextY = y + dirY[order[index][dir][i]];

            if (!isValid(nextX, nextY)) {
                continue;
            }

            if (smell[nextX][nextY][index] > 0) {
                sharkPos[index].set(0, new Pos(nextX, nextY, order[index][dir][i]));
                map[x][y]= 0;
                map[nextX][nextY] = index;
                return;
            }
        }
    }

    private static void makeSmell() {
        for (int i = 1; i <= m; i++) {
            if (!sharkPos[i].isEmpty())
                smell[sharkPos[i].get(0).x][sharkPos[i].get(0).y][i] = k;
        }
    }

    private static void removeSmell() {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int s = 1; s <= m; s++) {
                    if (smell[i][j][s] > 0) {
                        smell[i][j][s]--;
                    }
                }
            }
        }
    }

    private static boolean isValid(int x, int y) {
        if (x < 0 || x >= n || y < 0 || y >= n) {
            return false;
        }
        return true;
    }
    static class Pos {
        int x;
        int y;
        int dir;
        Pos (int x, int y, int dir) {
            this.x = x;
            this.y = y;
            this.dir = dir;
        }
    }
}