PS/삼성SDS알고리즘특강
[SDS 알고리즘 특강 복습] 5719 거의 최단 경로 (다익스트라)
2soon2soon
2025. 2. 19. 15:35
https://www.acmicpc.net/problem/5719
다익스트라 응용 문제.
역추적 아이디어가 필요.
내가 실수한 부분은 여러가지임
1. arraylist remove되는지 안되는지를 몰랐는데 -> 해보니까 안됨.
그래서 remove확인 하는법 확인하려고 답지를 봤는데 답지에서도 remove안씀. flag를 씀..
반성해야함 remove안되면 다른 방법 모색했어야했는데 무조건 remove된다고 생각했음.
실전스럽지 못했음.
2. 방문한 최단경로를 [V][V]에 저장했는데 이렇게하니까 메모리초과뜸.
[E]에 저장하는게 25배 메모리 덜 소요.
3. DP적 사고도 해줘야함. 이미 방문한 노드에 대해서는 쓸데없는 계산하지 않도록..!!
얻어 갈 것이 굉장히 많은 문제로 보임!!
복습해서 다 얻어가자. 유사한 문제가 출제될 것도 같으니 확실히 가져가자!!
<내 정답 코드>
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Array;
import java.util.*;
public class Main {
static int V, E, S, D, INF = 987654321;
static ArrayList<ArrayList<int[]>> edge;
static ArrayList<ArrayList<int[]>> reverseEdge;
static int[] used;
static PriorityQueue<int[]> pq;
static int[] dist;
static Queue<Integer> q;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
StringBuilder sb = new StringBuilder();
while(true) {
st = new StringTokenizer(br.readLine());
V = Integer.parseInt(st.nextToken());
E = Integer.parseInt(st.nextToken());
if(V==0 && E==0) break;
st = new StringTokenizer(br.readLine());
S = Integer.parseInt(st.nextToken());
D = Integer.parseInt(st.nextToken());
edge = new ArrayList<>();
reverseEdge = new ArrayList<>();
used = new int[E];
dist = new int[V];
pq = new PriorityQueue<>((o1, o2) -> {
return o1[1] - o2[1];
});
q = new LinkedList<>();
for (int i = 0; i < V; i++) {
dist[i] = INF;
edge.add(new ArrayList<>());
reverseEdge.add(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());
edge.get(a).add(new int[]{b, c, i});
reverseEdge.get(b).add(new int[]{a, c, i});
}
dist[S] = 0;
pq.add(new int[]{S, 0});
int[] cur;
int node, cost, next, w, ri;
while (!pq.isEmpty()) {
cur = pq.poll(); // 노드와 비용 cur에 저장
node = cur[0];
cost = cur[1];
// 뽑은 노드에 대해 연결된 노드들까지의 비용 재계산 및 pq에 푸시
for (int i = 0; i < edge.get(node).size(); i++) {
next = edge.get(node).get(i)[0];
w = edge.get(node).get(i)[1];
if (dist[next] > dist[node] + w) {
dist[next] = dist[node] + w;
pq.add(new int[]{next, dist[next]});
}
}
}
/*
D부터 시작해서 인접한 노드 poll
[인접한 노드까지 비용] + [인접노드 -> 현재노드 간선 비용] == [현재노드까지의 비용 이면]
해당 간선 삭제, 인접노드를 푸시
by BFS
*/
q.add(D);
int curr;
while (!q.isEmpty()) {
curr = q.poll();
for (int i = 0; i < reverseEdge.get(curr).size(); i++) {
next = reverseEdge.get(curr).get(i)[0];
w = reverseEdge.get(curr).get(i)[1];
ri = reverseEdge.get(curr).get(i)[2];
if(used[ri] == 1) continue;
if (dist[next] + w == dist[curr]) {
// edge.get(next).remove(new int[]{node, w});
used[ri] = 1;
q.add(next);
}
}
}
/*
간선 제거후 재 다익스트라.
*/
for (int i = 0; i < V; i++) {
dist[i] = INF;
}
dist[S] = 0;
pq.add(new int[]{S, 0});
while (!pq.isEmpty()) {
cur = pq.poll(); // 노드와 비용 cur에 저장
node = cur[0];
cost = cur[1];
// 뽑은 노드에 대해 연결된 노드들까지의 비용 재계산 및 pq에 푸시
for (int i = 0; i < edge.get(node).size(); i++) {
next = edge.get(node).get(i)[0];
w = edge.get(node).get(i)[1];
ri = edge.get(node).get(i)[2];
if (dist[next] > dist[node] + w && used[ri] == 0) {
dist[next] = dist[node] + w;
pq.add(new int[]{next, dist[next]});
}
}
}
sb.append(dist[D] == INF ? -1 + "\n" : dist[D] + "\n");
}
System.out.println(sb.toString());
}
}