백준 2307번 JAVA : 도로검문

문제

백준 문제 링크 : https://www.acmicpc.net/problem/2307

풀이전략

  • 다익스트라 알고리즘을 사용한다.

    • 거리 즉 가중치가 항상 양의 정수이기 때문에 다익스트라로 최단거리를 구해야 한다..
  • 모든 간선을 막을 경우 시간이 초과된다.

    • 따라서 범죄용의자의 최단거리를 이루는 path에 해당하는 간선들만 막으면서 최단거리를 구해 지연시간의 최대를 구해야한다.

코드

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


// 틀린이유 : 메모리초과 쓸데없이 Pair까지 만들어버림
// 틀린이유2 :  path만 따로 for문을 돌릴 생각을 하지 못했

// 배운점 : path만 따로 돌리는 법을 다익스트라에서 생각해보자
// 배운점2 : for문을 창의적으로도 돌릴수 있다.
// 배운점3 : 다익스트라의 path를 다음과같이 구할수 있음을 기억하자


public class Main {

	static class Node{
		public int v, dis;

		public Node(int v, int dis) {
			super();
			this.v = v;
			this.dis = dis;
		}

	}
	static ArrayList<Node>[] graph;
	static int[] distance;
	static int[] path;
	static int N, M;

	static int shortPath() {
		Arrays.fill(distance, Integer.MAX_VALUE);
		PriorityQueue<Node> pq = new PriorityQueue<>((e1,e2)->{return e1.dis - e2.dis;});
		distance[1] = 0;
		pq.add(new Node(1,0));
		while(!pq.isEmpty()) {
			Node now = pq.poll();

			if(distance[now.v] < now.dis ) continue;

			for(Node next : graph[now.v]) {

				if(distance[next.v] > distance[now.v] + next.dis) {
					distance[next.v] = distance[now.v] + next.dis;
					pq.add(new Node(next.v, distance[next.v]));
					path[next.v] = now.v;
				}
			}
		}
		return distance[N];
	}

	static int otherPath(int from, int to) {
		PriorityQueue<Node> pq = new PriorityQueue<>((e1,e2)->{return e1.dis - e2.dis;});
		Arrays.fill(distance, Integer.MAX_VALUE);
		distance[1] = 0;
		pq.add(new Node(1,0));
		while(!pq.isEmpty()) {
			Node now = pq.poll();

			if(distance[now.v] < now.dis ) continue;

			for(Node next : graph[now.v]) {
				if(now.v == from && next.v == to) continue;

				if(distance[next.v] > distance[now.v] + next.dis) {
					distance[next.v] = distance[now.v] + next.dis;
					pq.add(new Node(next.v, distance[next.v]));
				}
			}
		}
		return distance[N];
	}

	public static void main(String[] args) throws Exception {
		System.setIn(new FileInputStream("src/input.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		StringTokenizer st = new StringTokenizer(br.readLine());

		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());

		graph = new ArrayList[N+1];
		distance = new int[N+1];
		// 최단 경로의 path구하기
		path = new int[N+1];

		for(int i=0; i<=N; i++) {
			graph[i] = new ArrayList<Node>();
		}

		for(int i=0; i<M; i++) {
			st = new StringTokenizer(br.readLine());
			int a = Integer.parseInt(st.nextToken());
			int b = Integer.parseInt(st.nextToken());
			int t = Integer.parseInt(st.nextToken());

			graph[a].add(new Node(  b, t));
			graph[b].add(new Node(  a, t));
		}


		int shortestPath = shortPath();
		int maxPath = 0;

		// 스킬
		// https://katastrophe.tistory.com/76 참고
		// path 대로 순차적으로 이동할 수 있도록 하는 for
		// [next정점이 INdex] 그 value 는 current 정점
		for(int i=N; i>0; i=path[i])
			maxPath = Math.max(maxPath, otherPath(path[i], i));


		if(maxPath == Integer.MAX_VALUE) bw.write("-1\n");
		else bw.write(Integer.toString(maxPath - shortestPath) + "\n");

		bw.flush();
		bw.close();
	}
}

회고

  • 최단거리로 이동하는 각 path를 조회할때 멋지게 for문으로 하는 방법을 알게되었다. 이런 스킬들은 익혀야한다.
  • path만 막으면 된다는 것을 생각하지 못했다. 기억하자.

Written by@Gomster
항상 노력하고 나아가는 백엔드 개발자가 되고 싶은 대학생입니다.

GitHub