티스토리 뷰

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

 

18223번: 민준이와 마산 그리고 건우

입력의 첫 번째 줄에 정점의 개수 V와 간선의 개수 E, 그리고 건우가 위치한 정점 P가 주어진다. (2 ≤ V  ≤ 5,000, 1 ≤ E ≤ 10,000, 1 ≤ P  ≤ V) 두 번째 줄부터 E개의 줄에 걸쳐 각 간선의 정보

www.acmicpc.net

 

문제

종강을 맞은 민준이는 고향인 마산으로 내려갈 계획을 짜고 있었다. 늘 그랬듯, 마산으로 갈 버스를 예약하려던 순간 민준이는 집으로 가는 다른 방법이 떠올랐다. 그것은 직접 지도를 보고 고향으로 가는 가장 짧은 길을 찾는 것이다.

그때, 먼저 고향으로 내려갔던 친구인 건우에게 연락이 왔다. 건우는 고향으로 내려가던 중 알 수 없는 일에 휘말려 외딴곳에 혼자 남겨지게 되었다. 건우는 유일한 구세주인 민준이에게 도움을 청한 것이었다. 그러나 마산의 남자인 민준이에게는 마산이 먼저였다. 민준이는 처량한 건우를 무시한 채 고향으로 떠나려고 했지만, 만약 고향으로 가는 길에 건우가 있다면 겸사겸사 도움을 줄 수 있을 것 같았다.

지도는 양방향 그래프 형태로 되어있다. 출발지는 1번 정점 마산은 V번 정점이다. 정점은 1~V까지 있다. 건우는 P번 정점에 있다.
그리고 항상 1번 정점에서 P번과 V번 정점으로 갈 수 있는 경로가 존재한다.
중복되는 간선과 자기 자신을 가리키는 간선은 존재하지 않는다.

아래와 같은 그래프가 있을 때

위의 경우는 최단 경로가 두 가지 있다.
1→3→4→5→6 또는 1→3→5→6 이다. 이것 중에서 건우가 있는 곳, 즉 4번 정점이 포함된 최단 경로가 있으므로 이 경우에는 민준이가 건우를 도울 수 있다.

민준이가 건우를 도와주는 경로의 길이가 최단 경로의 길이보다 길어지지 않는다면, 민준이는 반드시 건우를 도와주러 간다.

어쩌면 지킬 수도 있는 민준이의 우정을 위해 우리가 도와주자!

 

유형 : 다익스트라

 

접근 방식

  • 우선 최단 경로가 2개 이상 존재할 수 있다. 그렇다면 모든 최단 경로를 구하고 그 경로에 건우가 포함되어 있는지 판단해야 할까?
    • 해보지는 않았지만 그렇게 해서 풀 수 는 있다고 생각은 한다. BUT 그럴 필요가 없다.
  • 다익스트라 알고리즘을 통해 우리가 알 수 있는 것은 출발지를 기점으로 도착지까지의 최단 거리 값이다.
    • 1 -> N 까지의 거리 (출발 -> 마산) , 1 -> K 까지의 거리(출발 -> 건우) , K -> N 까지의 거리 (건우 -> 마산)
    • 위 3 값만 안다면 우리는 건우를 태울 수 있다는 것을 판단할 수 있다.
    • 즉 (1->N) == (1->K) + (K->N)인 것을 판단하면 된다.
  • 출발지 , 건우의 위치를 시작점으로 하는 다익스트라 알고리즘을 2번 수행하자
    • 그리고 거리 값을 비교하여 정답을 추출한다.

전체 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int n = 0;
    static int m = 0;

    static int k = 0;

    static ArrayList<Node>[] graph;

    static int[][] dis;


    public static void main(String[] args) throws Exception {
        StringBuilder sb = new StringBuilder();
        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());

        graph = new ArrayList[n+1];
        for(int i=1;i<=n;i++){
            graph[i] = new ArrayList<>();
        }

        for(int i=1;i<=m;i++){
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());

            graph[x].add(new Node(y,v));
            graph[y].add(new Node(x,v));
        }

        dis = new int[n+1][2];

        for(int i=0;i<=1;i++){
            if(i == 0){
                find(1,0);
            }else{
                find(k,1);
            }
        }

        if(dis[n][0] == Integer.MAX_VALUE || dis[k][0] ==Integer.MAX_VALUE || dis[n][1]== Integer.MAX_VALUE){
            System.out.println("GOOD BYE");
        }else if(dis[n][0] != dis[k][0] + dis[n][1]){
            System.out.println("GOOD BYE");
        }
        else{
            System.out.println("SAVE HIM");
        }

        br.close();
    }

    static void find(int num,int cur){
        for(int i=1;i<=n;i++){
            dis[i][cur] = Integer.MAX_VALUE;
        }
        dis[num][cur] = 0;

        PriorityQueue<Node> pq = new PriorityQueue<>(
                (x,y) -> x.v - y.v
        );

        pq.add(new Node(num,0));

        while(!pq.isEmpty()){
            Node tmp = pq.poll();

            for(Node next : graph[tmp.v]){
                if(dis[next.v][cur] > dis[tmp.v][cur] + next.c){
                    dis[next.v][cur] = dis[tmp.v][cur] + next.c;
                    pq.add(new Node(next.v,dis[next.v][cur]));
                }
            }
        }

    }
}
class Node{
    int v;
    int c;

    Node(int v,int c){
        this.v = v;
        this.c = c;
    }
}

'알고리즘 > 백준' 카테고리의 다른 글

백준 1379 (강의실 2) - java  (1) 2023.11.22
백준 16469 (소년 점프) - java  (1) 2023.11.21
백준 11952 (좀비) - java  (1) 2023.11.20
백준 22116 (창영이와 퇴근) - java  (1) 2023.11.20
백준 2565 (전깃줄) - java  (1) 2023.11.20