ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 23290
    Java/코딩테스트 2023. 4. 8. 23:25

    결국 3차원 배열로 풀어야 했던 문제..

    🐟 같은 방향 보고 있는 물고기 2마리 이상이 같은 칸에 존재할 수도 있다. 이걸 되게 고민했는데 3차원 배열 쓰는게 더 편한것 같다... 

    🐟그리고 계속 실수했던 부분이 냄새를 삭제하는거... 상어가 움직이기 전에 각 smell[][] 감소시켜줘야한다. 상어가 움직이고 나서 감소해주면 갱신된 상태에서 감소시키는거라 계속 답이 틀림 

     

    진짜 너무 복잡했다... ㅎ 

    아직 코딩 멀었다~.~...


     

    🐟 변수

    temp는 방향까지 저장한 것

    fishAmountMap은 단순 해당 좌표에 몇마리 있는지만 저장한 것 (상어가 먹을 때는 방향상관없이 같은 칸에 있는거 다먹으니까)

    static int m, s;
    
    // 물고기의 8방향
    public static int[] fishX= {0, -1, -1, -1, 0, 1, 1, 1};
    public static int[] fishY = {-1, -1, 0, 1, 1, 1, 0, -1};
    
    // 상어의 4방향, 상좌하우 순서
    public static int[] sharkX = {-1, 0, 1, 0};
    public static int[] sharkY = {0, -1, 0, 1};
    
    // 상어 현재 위치 
    static Pos shark;
    
    static int answer;
    
    // 가장 많이 먹을 수 있는 이동방향 
    static int[] maxEatWay;
    
    // 물고기 총 마리 수 
    static int fishAmount;
    
    // 각 칸 당 물고기 수 
    static int[][] fishAmountMap;
    
    // 원본 배열, 마지막 단계에서 복제된 물고기 합쳐주기 위해 사용 
    static int[][][] map = new int[4][4][8];
    
    // 냄새 배열, 상어가 지나간 자리는 2로 만든다. 
    static int[][] smell = new int[4][4];
    
    // 물고기 이동시마다 temp를 초기화하여 사용, 상어이동까지 끝나면 temp와 map을 합침 
    static int[][][] temp;

    🐟 로직 순서 

    물고기 움직이기(여기서 temp 배열 만든다)  

    상어가 가장 많이 먹을 수 있는 방법, 먹을 수 있는 물고기 수 초기화

    냄새 제거 

    상어의 경로 탐색

    상어 실제로 움직이기

    temp와 map 합치기

    public static void magic() {
            fishMove();
            maxEatWay = new int[3];
            fishAmount = -11;
            removeSmell();
            findSharkWay();
            sharkMove();
            mergeArray();
    }

     

    1. 물고기 움직이기 

    public static void fishMove() {
            fishAmountMap = new int[4][4];
            temp = new int[4][4][8];
            // 모든 칸에 대해
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 4; j++) {
    
                    // 8방향 탐색 시작
                    for (int d = 0; d < 8; d++) {
                        if (map[i][j][d] == 0) {
                            continue;
                            // i, j 칸에 d 방향의 물고기는 없다는 뜻
                        } else {
                            int tempDir = d;
                            while (true) {
                                int nextX = i + fishX[tempDir];
                                int nextY = j + fishY[tempDir];
    
                                if (!isValid(nextX, nextY)
                                        || smell[nextX][nextY] > 0
                                        || (nextX == shark.x && nextY == shark.y)) {
                                    tempDir--; // 반시계방향으로 돌기 때문에 -1
                                    if (tempDir == -1) {
                                        tempDir = 7;
                                    }
                                    // 탐색 다 해봤는데도 안나와서 원래 방향으로 돌아온 케이스
                                    // 오리지널 맵에서 다시 데이터 꺼내와서 저장
                                    if (tempDir == d) {
                                        temp[i][j][d] += map[i][j][d];
                                        fishAmountMap[i][j] += map[i][j][d];
                                        break;
                                    }
                                    continue;
                                }
                                // 갈 수 있는 경우 현 위치의 것을 이동할 위치에다가 옮겨서 저장
                                temp[nextX][nextY][tempDir] += map[i][j][d];
                                fishAmountMap[nextX][nextY] += map[i][j][d];
                                break;
                            }
                        }
                    }
                }
            }
    }

     2. 냄새 없애기 

    public static void removeSmell() {
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 4; j++) {
                    if (smell[i][j] > 0) {
                        smell[i][j]--;
                    }
                }
            }
    }

    3. 상어의 경로 찾기 

    maxEatWay = new int[3];
    fishAmount = -11;

    public static void findSharkWay() {
            // 현재 상어 위치
            int x = shark.x;
            int y = shark.y;
            // 먹은양
            int eaten = 0;
            
            // 총 3칸을 이동하므로 3중 for문을 4번씩 돌린다(4방향 탐색)
            // 갔던 곳을 또 갈 수 있다. 이 때 물고기 카운트 중복해서 세면 안된다. 
            for (int i = 0; i < 4; i++) {
                int firstX = x + sharkX[i];
                int firstY = y + sharkY[i];
                if (!isValid(firstX, firstY)) {
                    continue;
                }
                eaten += fishAmountMap[firstX][firstY];
                for (int j = 0; j < 4; j++) {
                    int secondX = firstX + sharkX[j];
                    int secondY = firstY + sharkY[j];
                    if (!isValid(secondX, secondY)) {
                        continue;
                    }
                    eaten += fishAmountMap[secondX][secondY];
                    for (int k = 0; k < 4; k++) {
                        int thirdX = secondX + sharkX[k];
                        int thirdY = secondY + sharkY[k];
    
                        if (!isValid(thirdX, thirdY)) {
                            continue;
                        }
                        
                        // 왔던 좌표가 아닌 경우에만 third 포지션의 물고기 먹기
                        if (firstX != thirdX || firstY != thirdY) {
                            eaten += fishAmountMap[thirdX][thirdY];
                        }
                        
    					// 현재 경로가 더 많이 먹은거면 갱신후 그 방향들 저장
                        if (fishAmount < eaten) {
                            fishAmount = eaten; 
                            maxEatWay[0] = i;
                            maxEatWay[1] = j;
                            maxEatWay[2] = k;
                        }
    
                        // 먹은거 차례로 빼주면서 최대값 찾기
                        if (firstX != thirdX || firstY != thirdY) {
                            eaten -= fishAmountMap[thirdX][thirdY];
                        }
                    }
                    eaten -= fishAmountMap[secondX][secondY];
                }
                eaten -= fishAmountMap[firstX][firstY];
            }
    }

    4. 상어를 해당 경로대로 이동 시키며 먹기 

    상어 지나간 칸에 temp에 새로운 배열 할당하고, fishAmountMap 도 0으로 초기화, 냄새 남기기 

    public static void sharkMove() {
            int x = shark.x;
            int y = shark.y;
    
            // 최대 물고기 먹을 수 있는 경로대로 상어 움직임
            for (int i = 0; i < 3; i++) {
                int dir = maxEatWay[i];
                x += sharkX[dir];
                y += sharkY[dir];
    
                if (fishAmountMap[x][y] != 0) {
                    temp[x][y] = new int[8]; // 오리지널 맵 바로 조작하는거 아님!!
                    fishAmountMap[x][y] = 0;
                    smell[x][y] = 2;
                }
            }
            // 다 먹으면 이동!
            shark = new Pos(x, y);
    }

    5. 복사된 원본과 상어가 먹은 배열 합치기 

    public static void mergeArray() {
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 4; j++) {
                    if (fishAmountMap[i][j] != 0) {
                        for (int d = 0; d < 8; d++) {
                            map[i][j][d] += temp[i][j][d];
                        }
                    }
                }
            }
    }

     

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

    프로그래머스 Hash 문제풀이 - Java  (0) 2023.04.26
    프로그래머스 Stack / Queue 문제풀이 - Java  (0) 2023.04.21
    백준 17142  (0) 2023.04.08
    백준 15686  (0) 2023.04.06
    백준 14503  (0) 2023.04.06
Designed by Tistory.