[백준 2589] 보물섬(Java)

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

알고리즘

목록 보기
37/172

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

이 문제는 bfs를 이용하여 풀 수 있습니다. 처음에 이 문제를 풀기 위해 첫 번째 보물의 위치와 두 번째 보물의 위치 모두 반복문으로 탐색해서 풀었는데 4중 for문 내에 bfs 코드가 동작하니 시간 초과가 나왔습니다. 따라서 이 문제는 조금 더 생각해서 풀어야 합니다.

가장 핵심적인 부분은 첫 번째 보물의 위치를 알면 두 번째 보물의 위치는 정해진다는 것입니다. 문제에서 두 보물은 최단 거리로 이동하는데 있어 가장 긴 시간이 걸리는 곳에 묻혀있습니다. 따라서 첫 번째 보물의 위치에서 가장 멀리 떨어진 위치가 바로 두 번째 보물이 묻혀 있는 위치입니다. 이 방식으로 반복문 수를 줄여 bfs로 결과를 출력하시면 되겠습니다.

다음은 코드입니다.

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

public class Main{
    static int N,M;
    static int res = 0;
    static boolean[][] req = new boolean[51][51];
    static boolean[][] check = new boolean[51][51];
    static int[] dy = {1,0,-1,0};
    static int[] dx = {0,1,0,-1};

    static void bfs(int i, int j){
        check[i][j] = true;
        Queue<Treasure> queue = new LinkedList<>();
        queue.add(new Treasure(i,j,0));

        // 첫 번째 보물 위치만 움직여서 결과 출력
        while(!queue.isEmpty()){
            Treasure curr = queue.poll();
            int y = curr.y;
            int x = curr.x;
            int cnt = curr.cnt;

            // 만약 첫 번째 보물이 두 번째 보물 위치까지 도달했다면 max와 최댓값 비교
            if(res < cnt) res = cnt;

            // 첫 번째 보물 위치 이동
            for(int dir=0;dir<4;dir++){
                int ny = y + dy[dir];
                int nx = x + dx[dir];
                if(ny<0 || ny>=N || nx<0 || nx>=M) continue;

                // 지나간 경로가 아니고 현재 위치가 땅이라면 큐에 cnt 증가시켜 저장
                if(!check[ny][nx] && req[ny][nx]){
                    check[ny][nx] = true;
                    queue.add(new Treasure(ny,nx,cnt+1));
                }
            }
        }
    }

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

        for(int i=0;i<N;i++){
            st = new StringTokenizer(br.readLine());
            String str = st.nextToken();
            for(int j=0;j<M;j++){
                req[i][j] = str.charAt(j) != 'W';
            }
        }

        // 첫 번째 보물 위치에 대응하는 두 번째 보물 위치는 정해져 있음
        // 따라서 첫 번째 보물만 bfs로 탐색
        for(int i=0;i<N;i++){
            for(int j=0;j<M;j++){
                check = new boolean[51][51];
                if(req[i][j]){
                    bfs(i,j);
                }
            }
        }
        System.out.println(res);
    }
}

class Treasure{
    int y;
    int x;
    int cnt;

    Treasure(int y, int x, int cnt){
        this.y = y;
        this.x = x;
        this.cnt = cnt;
    }
}

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

0개의 댓글