백준 알고리즘/Java
[백준] 1504. 특정한 최단 경로 - Java
리버🐦🔥
2025. 5. 22. 03:32
https://www.acmicpc.net/problem/1504
⭐️ 중요 포인트
1. 기본 다익스트라와 동일. 다만,
경로 1 : (1번) -> (v1) -> (v2) -> (N번) = dijkstra(1, v1) + dijkstra(v1, v2) + dijkstra(v2, n)
경로 2 : (1번) -> (v2) -> (v1) -> (N번) = dijkstra(1, v2) + dijkstra(v2, v1) + dijkstra(v1, n)
경로를 이렇게 두 가지로 나누고, 각 경로마다 다익스트라를 돌려 하나의 전체 경로의 합을 구한다.
그 후 두 경로 중 작은 값을 비교(만약 경로가 이어져있지 않다면 -1을 리턴)
+ 첫 번째 코드 아래에 mergePath()를 통해 더 간결한 코드가 있습니다!
<경로가 이어져있지 않다면 distances가 0일것이기 때문에 -1을 리턴하는 방식으로 해결한 코드>
import java.util.*;
import java.io.*;
public class P1504 {
// Class
static class Edge {
int to;
int weight;
Edge(int to, int weight) {
this.to = to;
this.weight = weight;
}
}
static class Node {
int num;
int cost;
Node(int num, int cost) {
this.num = num;
this.cost = cost;
}
}
// Variable
static BufferedReader br;
static BufferedWriter bw;
static int n;
static int e;
static int v1;
static int v2;
static int answer;
static Map<Integer, List<Edge>> graph;
static Comparator<Node> comp = new Comparator<>() {
// pq cost기준 오름차순 정렬
@Override
public int compare(Node n1, Node n2) {
return n1.cost - n2.cost;
}
};
// Method
static void init() throws IOException {
br = new BufferedReader(new InputStreamReader(System.in));
bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
e = Integer.parseInt(st.nextToken());
answer = 0;
graph = new HashMap<>();
}
static void addEdge(int u, int v, int w) {
graph.computeIfAbsent(u, k -> new ArrayList<>()).add(new Edge(v, w));
graph.computeIfAbsent(v, k -> new ArrayList<>()).add(new Edge(u, w));
}
static void printGraph() {
for (int i = 1; i <= n; i++) {
System.out.println("<" + i + ">");
for (Edge e: graph.getOrDefault(i, Collections.emptyList())) {
System.out.println(e.to + " " + e.weight);
}
}
}
static void solve() throws IOException {
for (int i = 0; i < e; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
int u = Integer.parseInt(st.nextToken());
int v = Integer.parseInt(st.nextToken());
int w = Integer.parseInt(st.nextToken());
// 그래프에 간선 추가(무방향)
addEdge(u, v, w);
}
StringTokenizer st = new StringTokenizer(br.readLine());
v1 = Integer.parseInt(st.nextToken());
v2 = Integer.parseInt(st.nextToken());
int firstPath1 = dijkstra(1, v1);
int firstPath2 = dijkstra(v1, v2);
int firstPath3 = dijkstra(v2, n);
// System.out.println(firstPath1 + " + " + firstPath2 + " + " + firstPath3);
int secondPath1 = dijkstra(1, v2);
int secondPath2 = dijkstra(v2, v1);
int secondPath3 = dijkstra(v1, n);
// System.out.println(secondPath1 + " + " + secondPath2 + " + " + secondPath3);
int firstPathResult = 0;
int secondPathResult = 0;
if (firstPath1 != -1 && firstPath2 != -1 && firstPath3 != -1) {
firstPathResult = firstPath1 + firstPath2 + firstPath3;
} else {
firstPathResult = Integer.MAX_VALUE;
}
if (secondPath1 != -1 && secondPath2 != -1 && secondPath3 != -1) {
secondPathResult = secondPath1 + secondPath2 + secondPath3;
} else {
secondPathResult = Integer.MAX_VALUE;
}
answer = Math.min(firstPathResult, secondPathResult) != Integer.MAX_VALUE ? Math.min(firstPathResult, secondPathResult) : -1;
}
static int dijkstra(int start, int end) throws IOException {
Queue<Node> pq = new PriorityQueue<>(comp);
Map<Integer, Integer> distances = new HashMap<>();
pq.offer(new Node(start, 0));
distances.put(start, 0);
while (!pq.isEmpty()) {
Node curNode = pq.remove();
int curNum = curNode.num;
int curCost = curNode.cost;
// default가 나오면 무조건 거짓이 됨으로 스킵하지 않고 실행 가능
if (curCost > distances.getOrDefault(curNum, Integer.MAX_VALUE)) {
continue;
}
for (Edge edge: graph.getOrDefault(curNum, Collections.emptyList())) {
int nextNum = edge.to;
int nextCost = curCost + edge.weight;
// 계산한 nextCost가 현재 방문된 Node의 Cost보다 작을 경우 pq에 넣기
if (nextCost < distances.getOrDefault(nextNum, Integer.MAX_VALUE)) {
pq.offer(new Node(nextNum, nextCost));
distances.put(nextNum, nextCost);
}
}
}
return distances.getOrDefault(end, -1);
}
public static void main(String[] args) throws IOException {
init();
solve();
bw.write(String.valueOf(answer));
bw.close();
br.close();
}
}
<mergePath() 메소드를 통해 반복되는 코드를 제거한 코드 - 최종>
import java.util.*;
import java.io.*;
public class P1504 {
// Class
static class Edge {
int to;
int weight;
Edge(int to, int weight) {
this.to = to;
this.weight = weight;
}
}
static class Node {
int num;
int cost;
Node(int num, int cost) {
this.num = num;
this.cost = cost;
}
}
// Variable
static BufferedReader br;
static BufferedWriter bw;
static int n;
static int e;
static int v1;
static int v2;
static int answer;
static Map<Integer, List<Edge>> graph;
static Comparator<Node> comp = new Comparator<>() {
// pq cost기준 오름차순 정렬
@Override
public int compare(Node n1, Node n2) {
return n1.cost - n2.cost;
}
};
// Method
static void init() throws IOException {
br = new BufferedReader(new InputStreamReader(System.in));
bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
e = Integer.parseInt(st.nextToken());
answer = 0;
graph = new HashMap<>();
}
static void addEdge(int u, int v, int w) {
graph.computeIfAbsent(u, k -> new ArrayList<>()).add(new Edge(v, w));
graph.computeIfAbsent(v, k -> new ArrayList<>()).add(new Edge(u, w));
}
static void printGraph() {
for (int i = 1; i <= n; i++) {
System.out.println("<" + i + ">");
for (Edge e: graph.getOrDefault(i, Collections.emptyList())) {
System.out.println(e.to + " " + e.weight);
}
}
}
static void solve() throws IOException {
for (int i = 0; i < e; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
int u = Integer.parseInt(st.nextToken());
int v = Integer.parseInt(st.nextToken());
int w = Integer.parseInt(st.nextToken());
// 그래프에 간선 추가(무방향)
addEdge(u, v, w);
}
StringTokenizer st = new StringTokenizer(br.readLine());
v1 = Integer.parseInt(st.nextToken());
v2 = Integer.parseInt(st.nextToken());
int firstPathResult = mergePath(dijkstra(1, v1), dijkstra(v1, v2), dijkstra(v2, n));
int secondPathResult = mergePath(dijkstra(1, v2), dijkstra(v2, v1), dijkstra(v1, n));
answer = Math.min(firstPathResult, secondPathResult) != Integer.MAX_VALUE ? Math.min(firstPathResult, secondPathResult) : -1;
}
static int mergePath(int p1, int p2, int p3) {
if (p1 != -1 && p2 != -1 && p3 != -1) {
return p1 + p2 + p3;
}
return Integer.MAX_VALUE;
}
static int dijkstra(int start, int end) throws IOException {
Queue<Node> pq = new PriorityQueue<>(comp);
Map<Integer, Integer> distances = new HashMap<>();
pq.offer(new Node(start, 0));
distances.put(start, 0);
while (!pq.isEmpty()) {
Node curNode = pq.remove();
int curNum = curNode.num;
int curCost = curNode.cost;
// default가 나오면 무조건 거짓이 됨으로 스킵하지 않고 실행 가능
if (curCost > distances.getOrDefault(curNum, Integer.MAX_VALUE)) {
continue;
}
for (Edge edge: graph.getOrDefault(curNum, Collections.emptyList())) {
int nextNum = edge.to;
int nextCost = curCost + edge.weight;
// 계산한 nextCost가 현재 방문된 Node의 Cost보다 작을 경우 pq에 넣기
if (nextCost < distances.getOrDefault(nextNum, Integer.MAX_VALUE)) {
pq.offer(new Node(nextNum, nextCost));
distances.put(nextNum, nextCost);
}
}
}
return distances.getOrDefault(end, -1);
}
public static void main(String[] args) throws IOException {
init();
solve();
bw.write(String.valueOf(answer));
bw.close();
br.close();
}
}