Skip to content

Commit 3a7c0df

Browse files
authored
Merge pull request #925 from AlgorithmWithGod/0224LJH
[20250919] BOJ / G2 / 타임머신 / 이종환
2 parents 676de70 + cddd2af commit 3a7c0df

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
```java
2+
import java.io.BufferedReader;
3+
import java.io.IOException;
4+
import java.io.InputStreamReader;
5+
import java.util.*;
6+
7+
class Main {
8+
9+
static int N, M, a, b, c;
10+
static List<List<Integer>> graph;
11+
static List<List<Integer>> reverseGraph;
12+
static final long INF = Long.MAX_VALUE / 2;
13+
14+
static class Node implements Comparable<Node> {
15+
int num;
16+
long cost;
17+
18+
public Node(int num, long cost) {
19+
this.num = num;
20+
this.cost = cost;
21+
}
22+
23+
@Override
24+
public int compareTo(Node n) {
25+
return Long.compare(this.cost, n.cost);
26+
}
27+
}
28+
29+
public static void main(String[] args) throws NumberFormatException, IOException {
30+
init();
31+
process();
32+
}
33+
34+
public static void init() throws NumberFormatException, IOException {
35+
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
36+
StringTokenizer st = new StringTokenizer(br.readLine());
37+
38+
N = Integer.parseInt(st.nextToken());
39+
M = Integer.parseInt(st.nextToken());
40+
a = Integer.parseInt(st.nextToken());
41+
b = Integer.parseInt(st.nextToken());
42+
c = Integer.parseInt(st.nextToken());
43+
44+
graph = new ArrayList<>();
45+
reverseGraph = new ArrayList<>();
46+
47+
for (int i = 0; i <= N; i++) {
48+
graph.add(new ArrayList<>());
49+
reverseGraph.add(new ArrayList<>());
50+
}
51+
52+
for (int i = 0; i < M; i++) {
53+
st = new StringTokenizer(br.readLine());
54+
int u = Integer.parseInt(st.nextToken());
55+
int v = Integer.parseInt(st.nextToken());
56+
57+
graph.get(u).add(v);
58+
reverseGraph.get(v).add(u);
59+
}
60+
}
61+
62+
public static void process() {
63+
// 1. 타임머신을 고려한 수정된 다익스트라
64+
long[] dist = modifiedDijkstra();
65+
66+
// 2. 결과 출력
67+
if (dist[N] == INF) {
68+
System.out.println("x");
69+
} else if (dist[N] <= -INF/2) { // 음의 무한대로 발산
70+
System.out.println("-inf");
71+
} else {
72+
System.out.println(dist[N]);
73+
}
74+
}
75+
76+
public static long[] modifiedDijkstra() {
77+
long[] dist = new long[N + 1];
78+
Arrays.fill(dist, INF);
79+
80+
// 타임머신 사이클 비용 계산을 위한 BFS
81+
int distBtoA = bfs(b, a);
82+
boolean cyclePossible = (distBtoA != -1);
83+
long cycleCost = cyclePossible ? (distBtoA - c) : 0;
84+
85+
// N에서 역방향으로 도달 가능한 노드들 찾기
86+
boolean[] reachableFromN = new boolean[N + 1];
87+
findReachable(N, reverseGraph, reachableFromN);
88+
89+
PriorityQueue<Node> pq = new PriorityQueue<>();
90+
dist[1] = 0;
91+
pq.add(new Node(1, 0));
92+
93+
// 음의 사이클 체크를 위한 방문 횟수 카운트
94+
int[] visitCount = new int[N + 1];
95+
96+
while (!pq.isEmpty()) {
97+
Node cur = pq.poll();
98+
99+
// 너무 많이 방문했으면 음의 사이클
100+
if (visitCount[cur.num] > N) {
101+
if (reachableFromN[cur.num]) {
102+
dist[N] = -INF;
103+
return dist;
104+
}
105+
continue;
106+
}
107+
108+
visitCount[cur.num]++;
109+
110+
// 일반 간선 처리
111+
for (int next : graph.get(cur.num)) {
112+
long newCost = dist[cur.num] + 1;
113+
if (newCost < dist[next]) {
114+
dist[next] = newCost;
115+
pq.add(new Node(next, newCost));
116+
}
117+
}
118+
119+
// 타임머신 처리 (a번 정점에서만)
120+
if (cur.num == a) {
121+
long newCost = dist[a] - c;
122+
if (newCost < dist[b]) {
123+
dist[b] = newCost;
124+
pq.add(new Node(b, newCost));
125+
126+
// 음의 사이클 감지
127+
if (cyclePossible && cycleCost < 0 && reachableFromN[a]) {
128+
dist[N] = -INF;
129+
return dist;
130+
}
131+
}
132+
}
133+
}
134+
135+
return dist;
136+
}
137+
138+
// BFS로 최단 거리 찾기 (가중치가 모두 1이므로)
139+
public static int bfs(int start, int end) {
140+
if (start == end) return 0;
141+
142+
Queue<Integer> q = new LinkedList<>();
143+
int[] dist = new int[N + 1];
144+
Arrays.fill(dist, -1);
145+
146+
q.add(start);
147+
dist[start] = 0;
148+
149+
while (!q.isEmpty()) {
150+
int cur = q.poll();
151+
152+
for (int next : graph.get(cur)) {
153+
if (dist[next] == -1) {
154+
dist[next] = dist[cur] + 1;
155+
q.add(next);
156+
157+
if (next == end) {
158+
return dist[next];
159+
}
160+
}
161+
}
162+
}
163+
164+
return -1;
165+
}
166+
167+
// 특정 노드에서 도달 가능한 모든 노드 찾기
168+
public static void findReachable(int start, List<List<Integer>> g, boolean[] reachable) {
169+
Queue<Integer> q = new LinkedList<>();
170+
q.add(start);
171+
reachable[start] = true;
172+
173+
while (!q.isEmpty()) {
174+
int cur = q.poll();
175+
176+
for (int next : g.get(cur)) {
177+
if (!reachable[next]) {
178+
reachable[next] = true;
179+
q.add(next);
180+
}
181+
}
182+
}
183+
}
184+
}
185+
```

0 commit comments

Comments
 (0)