ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 19237
    Java/코딩테스트 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;
            }
        }
    }
    

     

     

     

     

     

     

     

    'Java > 코딩테스트' 카테고리의 다른 글

    백준 23288  (0) 2023.10.13
    백준 20055  (0) 2023.10.13
    백준 20057  (0) 2023.10.12
    백준 21608  (0) 2023.10.11
    백준 20056  (0) 2023.10.10
Designed by Tistory.