ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 1504번 특정한 최단 경로 (JAVA)
    알고리즘(Algorithm)/다익스트라(Dijkstra) 2022. 4. 15. 18:26

    백준 1504번 특정한 최단 경로 (JAVA)

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

     

    1504번: 특정한 최단 경로

    첫째 줄에 정점의 개수 N과 간선의 개수 E가 주어진다. (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000) 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존

    www.acmicpc.net

    문제

    방향성이 없는 그래프가 주어진다. 세준이는 1번 정점에서 N번 정점으로 최단 거리로 이동하려고 한다. 또한 세준이는 두 가지 조건을 만족하면서 이동하는 특정한 최단 경로를 구하고 싶은데, 그것은 바로 임의로 주어진 두 정점은 반드시 통과해야 한다는 것이다.

    세준이는 한번 이동했던 정점은 물론, 한번 이동했던 간선도 다시 이동할 수 있다. 하지만 반드시 최단 경로로 이동해야 한다는 사실에 주의하라. 1번 정점에서 N번 정점으로 이동할 때, 주어진 두 정점을 반드시 거치면서 최단 경로로 이동하는 프로그램을 작성하시오.

    입력

    첫째 줄에 정점의 개수 N과 간선의 개수 E가 주어진다. (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000) 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존재하며, 그 거리가 c라는 뜻이다. (1 ≤ c ≤ 1,000) 다음 줄에는 반드시 거쳐야 하는 두 개의 서로 다른 정점 번호 v1과 v2가 주어진다. (v1 ≠ v2, v1 ≠ N, v2 ≠ 1) 임의의 두 정점 u와 v사이에는 간선이 최대 1개 존재한다.

    출력

    첫째 줄에 두 개의 정점을 지나는 최단 경로의 길이를 출력한다. 그러한 경로가 없을 때에는 -1을 출력한다.


    소스 코드

    - 다익스트라 문제

    - 방향성이 없는 그래프 = 무방향(=양방향) 인접리스트 구성 필요

    - cost 초기값인 INF 는 오버플로우 나지 않도록 200,000(E의 최대값) * 1,000(c의 최대값) 값으로 설정

    - 목적지와, 목적지의 비용(거리)를 담는 Node class 생성하여 사용

    - 경로는 크게 두 가지 : 1 → v1 → v2 → N와 1 → v2 → v1 → N

    - 두 가지 경로 중 더 작은 값을 출력

    - 이 때 두 경로 모두 INF와 같거나 INF보다 큰 값이 나오면 경로가 없다는 의미이기 때문에 -1 출력

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.PriorityQueue;
    import java.util.StringTokenizer;
    
    public class Main {
        private static int N, E, Ans; // N:정점, E:간선
        private static int INF = 200000000; //200,000 * 1,000
        private static ArrayList<Node>[] adjList;
        private static int[] cost;
        private static boolean[] visited;
        private static class Node implements Comparable<Node>{
            int dest, cost; //dest: 목적지, cost: 거리
            public Node(int dest, int cost){
                this.dest = dest;
                this.cost = cost;
            }
            @Override
            public int compareTo(Node o){
                return this.cost - o.cost; //cost 기준 오름차순 정렬
            }
        }
        public static void main(String[] args) throws Exception{
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
            StringTokenizer st;
    
            Ans = 0;
            st = new StringTokenizer(br.readLine());
            N = Integer.parseInt(st.nextToken());
            E = Integer.parseInt(st.nextToken());
    
            adjList = new ArrayList[N+1];
            cost = new int[N+1];
            visited = new boolean[N+1];
    
            //인접리스트 초기화
            for (int i = 0; i < N+1; i++) {
                adjList[i] = new ArrayList<>();
            }
    
            for (int i = 0; i < E; i++) {
                st = new StringTokenizer(br.readLine());
                int a = Integer.parseInt(st.nextToken()); //출발지
                int b = Integer.parseInt(st.nextToken()); //도착지
                int c = Integer.parseInt(st.nextToken()); //비용(거리)
                adjList[a].add(new Node(b, c));//단방향인 경우 이것만 해도 됨
                adjList[b].add(new Node(a, c));//무방향(양방향)은 이것도 해야 함
            }
            st = new StringTokenizer(br.readLine());
            int v1 = Integer.parseInt(st.nextToken());
            int v2 = Integer.parseInt(st.nextToken());
    
            int ans1 = 0; // 1 > v1 > v2 > N
            ans1 += dijkstra(1, v1);
            ans1 += dijkstra(v1, v2);
            ans1 += dijkstra(v2, N);
    
            int ans2 = 0; // 1 > v2 > v1 > N
            ans2 += dijkstra(1, v2);
            ans2 += dijkstra(v2, v1);
            ans2 += dijkstra(v1, N);
    
            if(ans1 >= INF && ans2 >= INF) Ans = -1; //경로가 없는 경우
            else Ans = Math.min(ans1, ans2); //경로가 있을 경우 더 작은 값
    
            bw.write(Ans+"\n");
            bw.flush();
            bw.close();
            br.close();
        }
        private static int dijkstra(int start, int end){
            //최저비용 기준 탐색경로 저장 위한 우선순위 큐
            PriorityQueue<Node> pq = new PriorityQueue<>();
            Arrays.fill(visited, false); //방문여부 체크 배열 false로 초기화
            Arrays.fill(cost, INF); //cost 배열 INF로 초기화
    
            cost[start] = 0; //시작점이기 때문에 거리 0으로 셋팅
            pq.add(new Node(start, 0));
    
            while (!pq.isEmpty()){
                Node now = pq.poll();
    
                if(visited[now.dest]) continue; //방문했던 정점이면 스킵
                visited[now.dest] = true; //미방문이면 방문으로(true)로 셋팅하고 for문 처리
    
                //간선 탐색
                for (Node next:adjList[now.dest]) {
                    if(cost[next.dest] > next.cost + now.cost){
                        cost[next.dest] = next.cost + now.cost;
                        pq.add(new Node(next.dest, cost[next.dest]));
                    }
                }
            }
    
            return cost[end]; //목적지 end 까지의 최단거리
        }
    }

    댓글

Designed by Tistory.