[백준 16236] 아기 상어(Java)

최민길(Gale)·2023년 1월 29일
1

알고리즘

목록 보기
25/172

문제 링크 : https://www.acmicpc.net/problem/16236

이 문제는 bfs와 문제의 조건을 하나씩 구현해나가면 풀 수 있습니다.

이 문제에서 가장 처리하기 어려웠던 부분은 같은 조건인 물고기가 여러 마리일 때 어떤 식으로 처리하는지에 관한 부분입니다. 저는 우선순위 큐를 커스텀하여 큐에 담기는 요소들의 정렬 기준을 설정하여 먹을 수 있는 물고기는 모두 큐에 넣고, 실제로 먹는 물고기는 큐에서 Poll한 값만을 먹는 방식으로 처리하였습니다.

다음은 코드입니다.

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

public class Main{
    static int N;
    static int[][] req = new int[21][21];
    static int res = 0;
    static Fish babyShark;
    static int[] dy = {-1,0,0,1};
    static int[] dx = {0,-1,1,0};

    static PriorityQueue<Fish> eatenFish = new PriorityQueue<>(new Comparator<Fish>() {
        @Override
        public int compare(Fish fish1, Fish fish2) {
            // 거리가 같다면
            if(fish1.dist == fish2.dist){
                // 높이가 같다면 가장 왼쪽의 물고기부터
                if(fish1.y == fish2.y) return fish1.x-fish2.x;
                    // 가장 위의 물고기부터
                else return fish1.y-fish2.y;
            }
            // 거리가 작은 순으로 정렬
            else return fish1.dist-fish2.dist;
        }
    });

    static void searchFish(){
        boolean[][] check = new boolean[21][21];
        check[babyShark.y][babyShark.x] = true;

        Queue<Fish> queue = new LinkedList<>();
        queue.add(babyShark);

        while(!queue.isEmpty()){
            Fish curr = queue.poll();

            // 상어 상하좌우로 이동
            for(int i=0;i<4;i++){
                int ny = curr.y + dy[i];
                int nx = curr.x + dx[i];
                if(ny<0 || ny>=N || nx<0 || nx>=N) continue;

                // 아직 지나가지 않은 공간일 경우
                int fishSize = req[ny][nx];
                if(!check[ny][nx]){
                    // 자기보다 크기가 작은 경우 먹은 물고기 리스트에 넣기
                    if(curr.size > fishSize && fishSize!=0){
                        eatenFish.add(new Fish(ny,nx,fishSize,0,curr.dist+1));
                        check[ny][nx] = true;
                        queue.add(new Fish(ny,nx, curr.size, curr.eatNum, curr.dist+1));
                    }

                    // 크기가 같은 경우 또는 빈칸인 경우 큐에 추가
                    if(curr.size == fishSize || fishSize==0){
                        check[ny][nx] = true;
                        queue.add(new Fish(ny,nx, curr.size, curr.eatNum, curr.dist+1));
                    }
                }
            }
        }

    }

    static void eatFish(){
        // 먹을 수 있는 물고기 큐에서 가장 앞의 물고기만 가져옴
        Fish fish = eatenFish.poll();

        // 물고기 위치 및 상어 위치 초기화
        babyShark.y = fish.y;
        babyShark.x = fish.x;
        req[fish.y][fish.x] = 0;

        // 상어 먹은 횟수 증가
        babyShark.eatNum++;

        // 상어가 먹은 횟수와 크기가 같다면 사이즈 증가 후 먹은 횟수 초기화
        if(babyShark.eatNum == babyShark.size){
            babyShark.size++;
            babyShark.eatNum=0;
        }

        // 상어 이동 거리 누적
        res += fish.dist;
    }

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine());

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

                // 아기 상어 위치 체크
                if(req[i][j]==9){
                    babyShark = new Fish(i,j,2,0,0);
                    req[i][j] = 0;
                }
            }
        }

        while(true){
            // 먹은 물고기 초기화
            eatenFish.clear();
            // 먹을 수 있는 물고기 탐색
            searchFish();
            // 먹을 수 있는 물고기가 없다면 상어가 이동한 거리 리턴
            if(eatenFish.isEmpty()) break;
            // 먹을 수 있는 물고기 있다면 물고기 먹기
            else eatFish();
        }
        System.out.println(res);
    }
}

class Fish{
    int y;
    int x;
    int size;
    int eatNum;
    int dist;

    Fish(int y, int x, int size, int eatNum, int dist){
        this.y = y;
        this.x = x;
        this.size = size;
        this.eatNum = eatNum;
        this.dist = dist;
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글