꾸물꾸물 졔의 개발공부

[백준] 1504 특정한 최단 경로 - JAVA 본문

알고리즘/백준

[백준] 1504 특정한 최단 경로 - JAVA

체제 2023. 8. 21. 16:14

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

 

 

[알고리즘]

  • 출발지에서 목적지까지의 최단 경로를 구하는 다익스트라 Dijkstra 
  • 1 → v1 → v2 → N / 1 → v2 → v1 → N 의 경로 중 최솟값 반환 
  • 경로가 존재하는지 확인하기 위한 flag값(isfirst, issecond)을 사용하여, 만약 둘다 경로가 없다면 -1 반환 

 

[설계]

  • (1 → v1 → v2 → N) / (1 → v1 → v2 → N) 에서의 모든 경로에 대해 최단거리를 구해야한다.  
  • 총 3번의 다익스트라를 실행한다. 
    1. 출발지: 1번 노드 (1 → v1, 1 → v2 의 최단거리) 
    2. 출발지: v1 노드 (v1 → v2, v1 → N의 최단거리) 
    2. 출발지: v2 노드 (v2 → v1, v2 → N의 최단거리) 
  • Node 클래스 
    1. 정점, 이동거리 저장 

    2. Comparable 인터페이스를 구현하여 이동거리 오름차순 정렬 
    3. 우선순위큐에 저장, 이동거리가 낮을수록 우선순위 ↑ 

 

[구현 과정]

  • List<ArrayList<Node>> list : 주어진 N개의 정점의 연결정보를 저장한 리스트 
  • int first : (1 → v1 → v2 → N) 경로의 최단거리
  • int second :  (1 → v1 → v2 → N) 경로의 최단거리
  • boolean isfirst, issecond : 위 두 경로가 존재하는지 여부 (false = 가능한 경로 없음) 
  • min_dis[] : 다익스트라 구현에서 출발지에서 각 정점까지의 최단 거리 

 

1. N개의 정점과 E개의 간선 정보를 입력받아 list 에 저장. (양방향이므로 a, b 모두 add) 

 

2. v1 → v2 / v2 → v1 의 경로를 탐색하기 위해 3번의 다익스트라를 실행한다. 

 

3. 다익스트라 

  • 출발정점, 0 add  
  • 현재 정점에서 이동할 수 있는 정점들을 탐색하며, min_dis 에 저장되어 있는 값 보다 현재 정점을 거쳐가는 거리가 더 짧을 경우 최단 거리를 갱신 
  • 갱신한 값 min_dis 에 저장하고, 큐에 add 
  • 큐가 빌 때 까지 반복

 

 

4. ( 1, v1, v2 ) 노드를 시작점으로 하여 3번의 다익스트라를 실행 한후, first / second 경로의 최단거리를 구한다.

 

5. 가능한 경로가 있는지 (flag 값 isfirst/ issecond)를 고려하여 최솟값을 출력. 

 


 

[소스 코드]

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

public class Main {
	static List<ArrayList<Node>> list = new ArrayList<>();
	static int N; 
	static class Node implements Comparable<Node>{
		int node;
		int weight;
		
		public Node(int node, int weight) {
			this.node=node;
			this.weight=weight; 
		}

		@Override
		public int compareTo(Node o) {
			return this.weight- o.weight; 
		}
	}
    
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
		StringTokenizer st;
		
		st = new StringTokenizer(br.readLine(), " "); 
		N = Integer.parseInt(st.nextToken()); 
		int E = Integer.parseInt(st.nextToken()); 
		
		for(int i=0; i<=N; i++) {
			list.add(new ArrayList<>()); 
		}
		
		while(E-- >0) {
			st= new StringTokenizer(br.readLine(), " ");
			int a = Integer.parseInt(st.nextToken()); 
			int b = Integer.parseInt(st.nextToken()); 
			int c = Integer.parseInt(st.nextToken()); 
			
			//양방향 저장 
			list.get(a).add(new Node(b,c)); 
			list.get(b).add(new Node(a,c)); 
			
		}
		
		st= new StringTokenizer(br.readLine(), " ");
		
		int v1= Integer.parseInt(st.nextToken());
		int v2= Integer.parseInt(st.nextToken());
		
		
		int first= 0; //v1 - v2 순
		int second = 0; //v2 -v1 순 
		
		boolean isfirst= true; //v1 -v2 경로 있는지 
		boolean issecond = true; //v2 - v1 경로 있는지 
		
		// 1->v1, 1->v2 경로의 최단거리 
		int[] start = dijkstra(1);
		if(start[v1] == Integer.MAX_VALUE) isfirst = false; 
		else first += start[v1]; 
		
		if(start[v2] == Integer.MAX_VALUE) issecond = false; 
		else second += start[v2]; 
		
		// v1-> v2, v1->N 경로의 최단거리 
		int[] v1_arr= dijkstra(v1); 
		if(v1_arr[v2] == Integer.MAX_VALUE) isfirst = false;
		else first += v1_arr[v2]; 
		
		if(v1_arr[N] == Integer.MAX_VALUE) issecond = false;
		else second += v1_arr[N]; 
		
		// v2-> v1, v2-> N 경로의 최단거리
		int[] v2_arr = dijkstra(v2);
		if(v2_arr[v1]== Integer.MAX_VALUE) issecond = false;
		else second += v2_arr[v1]; 
		
		if(v2_arr[N] == Integer.MAX_VALUE) isfirst= false;
		else first += v2_arr[N]; 
		
		
		if(!isfirst && !issecond) System.out.println(-1);
		else {
			if(!isfirst) first= Integer.MAX_VALUE;
			if(!issecond) second = Integer.MAX_VALUE;
			
			System.out.println(Math.min(first, second));
			
		}
 		
	}//end of main 
	
	static int[] dijkstra(int n) {
		PriorityQueue<Node> que= new PriorityQueue<>();
		int[] min_dis = new int[N+1]; 
		Arrays.fill(min_dis, Integer.MAX_VALUE);
		
		que.add(new Node(n,0));
		min_dis[n]=0; 
		
		while(!que.isEmpty()) {
			Node no = que.poll();
			int node= no.node;
			int weight = no.weight;
			
			for(Node next : list.get(node)) {
				int nnode = next.node;
				int nweight= next.weight;
				
				if(min_dis[nnode] > weight + nweight) {
					min_dis[nnode] = min_dis[node]+nweight;
					que.add(new Node(nnode, min_dis[nnode])); 
				}
			}
		}
		
		return min_dis; 
		
	}
}//end of class

 

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

[백준] 2665 미로만들기 - JAVA  (1) 2023.08.23
[백준] 1261 알고스팟 - JAVA  (0) 2023.08.22
[백준] 5972 택배 배송 - JAVA  (0) 2023.08.17
[백준] 2096 내려가기 - JAVA  (0) 2023.08.16
[백준] 1520 내리막 길 - JAVA  (0) 2023.08.15