백준 1504 특별한 최단 경로 [자바]

baekjoon 1504 특별한 최단 경로

java

문제 분석

  • 방향성 없는 그래프
  • 1에서 N까지 이동하는 최단경로를 찾을건데,
  • 임의의 두 정점을 반드시 통과하는 최단경로.
  • 한번 이동했던 정점, 간선 모두 다시 이용할 수 있음

입력조건

정점의 수 N, 간선의 수 E
E개의 줄에 걸쳐{
	시작점 a, 끝점 b, 가중치 c
}
반드시 거쳐야 하는 두 정점 v1, v2

풀이과정

  • 다익스트라
  • v1과 v2사이의 거리는 일정하므로
  • 답은 (1-v1 거리) + (v2-N 거리) + (v1-v2 거리)이거나, (1-v2 거리) + (v1-N 거리) + (v1-v2 거리) 중 하나.

코드 구성

v1에서 모든 노드로 가는 최단거리를 구하고,

v2에서 모든 노드로 가는 최단거리를 구함.

  • 평범하게 다익스트라 코드
public static void dijkstra(int[] from, int v) {
    PriorityQueue<node> pq = new PriorityQueue<>();
    pq.add(new node(v, 0));

    while(!pq.isEmpty()) {
        node a = pq.poll();
        if(from[a.v] < 8000000) continue;
        from[a.v] = a.w; 

        for(node nd : grp[a.v]) {
            if(from[nd.v] < 8000000) continue;
            pq.add(new node(nd.v, nd.w + a.w));
        }
    }
}
  • 위 코드를 두 번 돌려서 각 위치로 가는 최솟값을 구한 다음, 가능한 두 개의 답 후보를 비교함.
int set1 = fromv1[1] + fromv2[N];
int set2 = fromv1[N] + fromv2[1];
int ans = Math.min(set1, set2) + fromv1[v2];
System.out.println(ans < 8000000 ? ans : -1 );

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class BJ1504_특정한최단경로 {
	public static class node implements Comparable<node> {
		int v, w;
		node(int v, int w){
			this.v = v;
			this.w = w;
		}
		@Override
		public int compareTo(node o) {
			return this.w - o.w;
		}
	}
	static ArrayList<node>[] grp;
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		int N = Integer.parseInt(st.nextToken());
		int E = Integer.parseInt(st.nextToken());
		grp = new ArrayList[N+1];
		for(int i = 1; i <= N; i++) grp[i] = new ArrayList<>();
		for(int i = 0; i < E; i++) {
			st = new StringTokenizer(br.readLine());
			int u = Integer.parseInt(st.nextToken());
			int v = Integer.parseInt(st.nextToken());
			int w = Integer.parseInt(st.nextToken());
			
			grp[u].add(new node(v, w));
			grp[v].add(new node(u, w));
		}
		st = new StringTokenizer(br.readLine());
		int v1 = Integer.parseInt(st.nextToken());
		int v2 = Integer.parseInt(st.nextToken());
		// 입결받기 끝.

		int[] fromv1 = new int[N+1]; Arrays.fill(fromv1, 8000000);
		int[] fromv2 = new int[N+1]; Arrays.fill(fromv2, 8000000);
		dijkstra(fromv1, v1);
		dijkstra(fromv2, v2);
		
		int set1 = fromv1[1] + fromv2[N];
		int set2 = fromv1[N] + fromv2[1];
		int ans = Math.min(set1, set2) + fromv1[v2];
		System.out.println(ans < 8000000 ? ans : -1 );
	}
	public static void dijkstra(int[] from, int v) {
		PriorityQueue<node> pq = new PriorityQueue<>();
		pq.add(new node(v, 0));
		
		while(!pq.isEmpty()) {
			node a = pq.poll();
			// 방문한 적이 있으면 지나가기.
			if(from[a.v] < 8000000) continue;
			// 방문처리
			from[a.v] = a.w; 
			
			for(node nd : grp[a.v]) {
				if(from[nd.v] < 8000000) continue;
				pq.add(new node(nd.v, nd.w + a.w));
			}
		}
	}
}