์ด๋ฒ ๋ฌธ์ ๋ ๋ฒจ๋ง-ํฌ๋๋ฅผ ์ต์ ํํ๋ SPFA ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํด๋ณด๊ธฐ ์ํด ๋์ด๋๊ฐ ์ด๋ ต์ง ์์ ๋ฌธ์ ์ง๋ง ํ์ด๋ณด์๋ค.
SPFA๋ฅผ ๋นจ๋ฆฌ ์ ๋ฆฌํ๊ณ ์ถ์ง๋ง ์ฐ์ ๋ฒจ๋งํฌ๋์ ํ์ต์ด ์ ํ๋์ด์ผ ํ๋ค. ๊ทธ๋ฌ๋ ๋ฒจ๋งํฌ๋๋ถํฐ ์ ๋ฆฌํด๋ณด์.
๋ฒจ๋งํฌ๋์ ํน์ง
- 1:n ์ต๋จ๊ฑฐ๋ฆฌ ์๊ณ ๋ฆฌ์ฆ์ด๋ค.
- ๋ค์ต์คํธ๋ผ๋ณด๋ค ๋๋ฆฌ๋ค.
- ๋ค์ต์คํธ๋ผ๋
O(nlogn)
, ๋ฒจ๋งํฌ๋๋O(V*E)
- ๋ชจ๋ ๋ ธ๋์ ๋ํด ๋ชจ๋ ๊ฐ์ ์ ๊ฒ์ฌํ๊ธฐ ๋๋ฌธ์ด๋ค.
- ๋ค์ต์คํธ๋ผ๋
- ์์๊ฐ์ ์ด ์๋๋ผ๋ ์๋ํ๋ค!
- ๋ค์ต์คํธ๋ผ์ ๊ฒฝ์ฐ ์์๊ฐ์ ์ด ํฌํจ๋๋ฉด ์ค๋ต์ ๋ด๋์ ๊ฐ๋ฅ์ฑ์ด ์๊ธด๋ค.
- ๋๋ฆฌ์ง๋ง ๋ฒจ๋งํฌ๋๋ฅผ ์ฌ์ฉํ ์ ๋ฐ์ ์๋ ๋ฌธ์ ๊ฐ ์๋ ๊ฒ.
- โ์์ ์ฌ์ดํดโ์ ๊ฒ์ถํ ์ ์๋ค!
- ์์ ์ฌ์ดํด์ n๋ฒ ๋ ธ๋์์ ์๊ธฐ์์ ์ผ๋ก ๋์์ฌ ๋ ๊ฐ์ค์น๊ฐ ์์๊ฐ ๋๋ ์ฌ์ดํด์ ๋งํ๋ค.
- n๋ฒ๋ ธ๋์์ n๋ฒ๋ ธ๋๋ก ๊ฐ๋ ๊ฑฐ๋ฆฌ๊ฐ 0 ์ดํ์ธ ์์๋ผ๋ฉด, ์ต๋จ๊ฑฐ๋ฆฌ๋ ์ด๋ป๊ฒ ๋๊ฒ ๋๊ฐ?
- ์์ ๋ฌดํ๋ ๊ฐ์ด ๋๋ฏ๋ก, ๊ฒ์ถ๋ง ํ๋ฉด ์ปดํจํฐ๋ ํ ์ผ์ ๋ค ํ ๊ฒ์ด๋ค.
๋ฌธ์ ํ์ด (๋ฒจ๋ง-ํฌ๋)
package ์์จํ์คํฐ๋.d240928;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
public class BOJ_1865 {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static int TC, n, m, w;
static List<int[]> graph;
static int[] dist;
private static void input() throws IOException {
st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
w = Integer.parseInt(st.nextToken());
graph = new ArrayList<>();
dist = new int[n + 1];
Arrays.fill(dist, Integer.MAX_VALUE);
int s, e, t;
for (int i = 0; i < m; i++) {
st = new StringTokenizer(br.readLine());
s = Integer.parseInt(st.nextToken());
e = Integer.parseInt(st.nextToken());
t = Integer.parseInt(st.nextToken());
graph.add(new int[] {s, e, t});
graph.add(new int[] {e, s, t});
}
for (int i = 0; i < w; i++) {
st = new StringTokenizer(br.readLine());
s = Integer.parseInt(st.nextToken());
e = Integer.parseInt(st.nextToken());
t = Integer.parseInt(st.nextToken());
graph.add(new int[] {s, e, -t});
}
}
private static boolean bellmanFord(int start) {
dist[start] = 0;
int now, next, cost, nextCost;
// ์ต์๊ฐ ๊ฐฑ์ . ๋ฆด๋์ธ์ด์
for (int v = 1; v <= n; v++) {
for (int e = 0; e < graph.size(); e++) {
now = graph.get(e)[0];
next = graph.get(e)[1];
cost = graph.get(e)[2];
nextCost = dist[now] + cost;
if (dist[now] != Integer.MAX_VALUE && dist[next] > nextCost) {
dist[next] = nextCost;
}
}
}
// ์์ ์ฌ์ดํด ์กด์ฌ ํ์ธ
for (int e = 0; e < graph.size(); e++) {
now = graph.get(e)[0];
next = graph.get(e)[1];
cost = graph.get(e)[2];
nextCost = dist[now] + cost;
if (dist[now] != Integer.MAX_VALUE && dist[next] > nextCost) {
return true;
}
}
return false;
}
public static void main(String[] args) throws Exception {
TC = Integer.parseInt(br.readLine());
boolean ans = false;
for (int testCase = 0; testCase < TC; testCase++) {
input();
for (int i = 1; i <= n; i++) {
if (dist[i] == Integer.MAX_VALUE) {
if (ans = bellmanFord(i)) {
System.out.println("YES");
break;
}
}
}
if (!ans) {
System.out.println("NO");
}
}
}
class Node {
int v, e;
public Node(int v, int e) {
this.v = v;
this.e = e;
}
}
}
๋ฒจ๋ง ํฌ๋๋ฅผ ์ดํดํจ์ ์์ด์ ์ ์ฝ๋๋ฅผ ๋ชจ๋ ๋ณผ ํ์๋ ์๋ค. ๋ค์ต์คํธ๋ผ์ ์ธํ ์ ๋ค๋ฅด๊ฒ ํ ๊ฒ์, ์ฐ๊ฒฐ ๊ฐ์ ์ (์ถ๋ฐ๋ ธ๋, ๋์ฐฉ๋ ธ๋, ๊ฐ์ค์น)๋ก ์ ์ฅํ๋ค๋ ๊ฒ.
for (int v = 1; v <= n; v++)
๋ฃจํ ๋ด๋ถ์์ ๋ชจ๋ ๊ฐ์ ์ ํตํด ์ต๋จ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์ ํด์ฃผ๋ ๊ณผ์ ์ โ๋ฆด๋ ์ธ์ด์ โ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.- ๋ฆด๋ ์ธ์ด์ ์ ๋ ธ๋์ ๊ฐฏ์๋งํผ ์คํํด ์ค๋ค.
- ์ ๊ณผ์ ์ ๋ง์น ํ, ํ๋ฒ์ ๋ฆด๋ ์ธ์ด์
์ ๋ ์งํํ๋ค ์ต์๊ฐ ๊ฐฑ์ ์ด ๋ค์ ๋ฐ์ํ๋ฉด ์ด๋ ์์์ฌ์ดํด์ ํฌํจํ ๊ทธ๋ํ์ด๋ค.
- ์ง๊ด์ ์ผ๋ก ์๊ฐํด๋ด๋, ๋ชจ๋ ๋ ธ๋๋ฅผ ๊ฑฐ์ณ๊ฐ๋ ๊ฒ ๋ณด๋ค ๋ ๊ธด ๊ฑฐ๋ฆฌ๋ฅผ ํตํด ๋ ์งง์ ๊ฑฐ๋ฆฌ๊ฐ ๋์จ๋ค๋ฉดโฆ ์์ ์ฌ์ดํด์ ํ์ฐ์ ์ผ๋ก ๊ฐ์ง๊ฒ ๋๋ค.
SPFA (Shortest Path Faster Algorithm) ํน์ง
- ๋๋์ด SPFA์ ๋ํด ์์๋ณด์.
- ๋ฒจ๋ง-ํฌ๋์ ๋ฒ ์ด์ค๋ฅผ ๊ฐ์ง๋ค.
- ๋ฒจ๋ง-ํฌ๋์์ ๋ชจ๋ ๊ฐ์ ์ ํตํด ๋ฆด๋ ์ธ์ด์ ์ ํ๋ ๊ณผ์ ์ โ๊ฐฑ์ ๋ ๋ ธ๋์ ์ฐ๊ฒฐ๋ ๊ทธ๋ํ๋ง์ ํตํดโ ๋ฆด๋ ์ธ์ด์ ์ ์ํํ๋ค.
- ์ด๋ ์ต์ ํ๋ฅผ ์ํ ์๊ณ ๋ฆฌ์ฆ์ผ ๋ฟ์ด๋ฉฐ, ์ฌ์ค ์ฝ๋ฉํ
์คํธ์์ ์ฃผ๋ ์ต์
์ ๊ฒฝ์ฐ์ ์ ์์๋ ์๊ฐ๋ณต์ก๋๊ฐ ์ฌ์ ํ
O(V * E)
์ด๋ค.- ๋ค๋ฅด๊ฒ ๋งํ๋ฉด ์๋ชป ๊ตฌํํ ์ ์๋์ ๋ฒจ๋งํฌ๋๋ณด๋ค ๋๋ ค์ง๋ค. ๊ฐ๋ฅํ๋ฉด Queue์ ๊ฐ์ ๋จ์ํ ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ด์ฉํ์ฌ ๊ตฌํํ์.
SPFA ๊ตฌํ๋ฐฉ๋ฒ์ ๋ชจ๋ฅด๊ณ ์ค์ค๋ก ์ต์ ํ๋ฅผ ํ์ ๋, Set์ ์ฌ์ฉํ๋๋ผ ์คํ๋ ค ๋๋ ค์ก๋ ๊ฒฝํ์ด ์๋ค
๋ฌธ์ ํ์ด (SPFA)
package ์์จํ์คํฐ๋.d240928;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class BOJ_1865_SPFA {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static int TC, n, m, w;
static List<int[]> graph[];
static int[] dist;
private static void input() throws IOException {
st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
w = Integer.parseInt(st.nextToken());
graph = new ArrayList[n + 1];
for (int i = 0; i <= n; i++)
graph[i] = new ArrayList<>();
dist = new int[n + 1];
Arrays.fill(dist, Integer.MAX_VALUE);
int s, e, t;
for (int i = 0; i < m; i++) {
st = new StringTokenizer(br.readLine());
s = Integer.parseInt(st.nextToken());
e = Integer.parseInt(st.nextToken());
t = Integer.parseInt(st.nextToken());
graph[s].add(new int[] {e, t});
graph[e].add(new int[] {s, t});
}
for (int i = 0; i < w; i++) {
st = new StringTokenizer(br.readLine());
s = Integer.parseInt(st.nextToken());
e = Integer.parseInt(st.nextToken());
t = Integer.parseInt(st.nextToken());
graph[s].add(new int[] {e, -t});
}
}
private static boolean spfa(int start) {
dist[start] = 0;
// ์ต์๊ฐ ๊ฐฑ์ . ๋ฆด๋์ธ์ด์
Queue<Integer> q = new ArrayDeque<>();
boolean[] inque = new boolean[n+1];
int[] cnt = new int[n+1];
q.add(start);
inque[start] = true;
int now, next, cost;
while (!q.isEmpty()) {
now = q.poll();
inque[now] = false;
for (int[] edge : graph[now]) {
next = edge[0];
cost = edge[1];
if (dist[next] > dist[now] + cost) {
dist[next] = dist[now] + cost;
if (!inque[next]) {
q.add(next);
inque[next] = true;
cnt[next]++;
if (cnt[next] > n)
return true;
}
}
}
}
return false;
}
public static void main(String[] args) throws Exception {
TC = Integer.parseInt(br.readLine());
boolean ans = false;
for (int testCase = 0; testCase < TC; testCase++) {
input();
for (int i = 1; i <= n; i++) {
if (dist[i] == Integer.MAX_VALUE) {
if (ans = spfa(i)) {
System.out.println("YES");
break;
}
}
}
if (!ans) {
System.out.println("NO");
}
}
}
class Node {
int v, e;
public Node(int v, int e) {
this.v = v;
this.e = e;
}
}
}
๋ฌ๋ผ์ง ๋ถ๋ถ๋ง ๋ณด์.
- input์์ ํน์ ๋ ธ๋์์ ์ถ๋ฐํ๋ ๊ฐ์ ์ ๋น ๋ฅด๊ฒ ๊ตฌ๋ถํ ์ ์๋๋ก ๊ฐ์ ์ ์ ๋ ฅ๋ฐ์๋ค.
- BellmanFord โ SPFA๋ก ๋์ด๊ฐ๋ฉฐ, ๊ฐฑ์ ๋ ๋ ธ๋๋ง์ ์ฒดํฌํด์ฃผ๊ธฐ ์ํด queue๋ฅผ ์ฌ์ฉํ๋ค.
- queue๋ ์์ฒด์ ์ค๋ณต๋ฐฉ์ง๊ฐ ์๋ค. ๋ ธ๋๊ฐ queue์ ์๋์ง ๊ฒ์ฌํด์ฃผ๋ inque๋ฐฐ์ด์ ๋ง๋ค์๋ค.
- ๊ณ์ฐ ํ์๊ฐ ๋ ธ๋์ ์๋ฅผ ๋์ด๊ฐ๋์ง ์ฒดํฌํด์ฃผ๊ธฐ ์ํด cnt ๋ฐฐ์ด์ ๋ง๋ค์๋ค. ์ด๋ฅผ ํตํด ์์ ์ฌ์ดํด์ ๊ฒ์ถํ๋ค.
์ฐ๊ฒฐ๋ ๊ฐ์ ์ ํตํด ์ต์๊ฐ์ด ๊ฐฑ์ ๋ ๋ ธ๋๋ง์ด ๋ค์ ๋ ธ๋๋ก ์ฐ๊ฒฐ๋๋ฉฐ ์ต์๊ฐ์ ๊ฐฑ์ ํ ์ ์๋ค! ๊ทธ๋์ ๊ฐฑ์ ๊ณผ ํจ๊ป ํ์ ๋ฃ์ด์ฃผ๋ ๊ฒ์ด๋ค.
์ํ
๋ฉ๋ชจ๋ฆฌ๋ 17๋ฉ๊ฐ๋ฐ์ดํธ ์ฆ๊ฐํ์ง๋ง ์๊ฐ์ ์ฝ 200ms ์ค์ผ ์ ์์๋ค.
๊ด์ฐฎ์ trade-off ๊ด๊ณ์ธ ๊ฒ ๊ฐ๋ค.
ํ๊ธฐ
-
๋ฌธ์ ์ ์ฝ๊ฐ์ ํจ์ ์ด ์๋ค๋ฉด, ๋ชจ๋ ๋ ธ๋๋ค์ด ์ฐ๊ฒฐ๋์ด ์์ง ์๊ธฐ์, ํ์์ ๋ฐ๋ผ ์ต๋จ๊ฑฐ๋ฆฌ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ๋ฌ ๋ฒ ์ํํด์ผ ํ๋ค๋ ์ ์ด๋ค.
-
SPFA๋ฅผ ๋ชฐ๋์ ๋, ๋ฒจ๋งํฌ๋๊ฐ ๋ชจ๋ ๊ฐ์ ์ ๋์์ผํ๋ค๋ ์ฌ์ค์ด ๋๋ฌด ๋นํจ์จ์ ์ด๋ผ ์๊ฐ์ด ๋ค์ด ์ฐ๊ฒฐ๋ ๊ฐ์ ๋ง์ ํตํด ๊ฐฑ์ ์ด ์ํ๋๋๋ก ๋ง๋ค๋ค๊ฐ
set
์ ์ผ๋ค.- ํ์ ๊ฐ์ ๋
ธ๋๊ฐ ๋ค์ด๊ฐ๋ ๊ฒ ์ซ์๊ณ ,
set
๋ enhanced for๋ฌธ์ ํตํด ์ํ๊ฐ ๊ฐ๋ฅํ๊ธฐ์ ๊ทธ๋ฐ ์ ํ์ ํ๋ค. - ๊ฒฐ๊ณผ๋ ๋์คํจ์๋ค. ๊ทธ๋๋ ์๊ฐ์ด ์คํ๋ ค ๋์๋ค.
- ์ข ๋ ์ฐพ์๋ณด๊ณ ๋์๋ Queue์ ์ค๋ณต์ฒดํฌ ๋ฐฐ์ด์ ์ฌ์ฉํ์ฌ ์ฑ๊ณต์ ์ผ๋ก ๊ตฌํํ ์ ์์๋ค.
- ์ต์ ์ ๊ฒฝ์ฐ์ ์๊ฐ์ ์ค์ฌ์ฃผ์ง ๋ชปํ๊ธฐ์, SPFA ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํ์ ์ ๊ตํ๊ฒ ํด์ผ ํ๋ค๋ ์ฌ์ค์ ๋ฐฐ์ ๋ค. (๋คํ์ธ๊ฑด ๋ณ๋ก ์ด๋ ต์ง๋ ์๋ค)
- ํ์ ๊ฐ์ ๋
ธ๋๊ฐ ๋ค์ด๊ฐ๋ ๊ฒ ์ซ์๊ณ ,
-
์ด๋ ๊ฒ ํ๋ฒ ๊ตฌํ์ ํด๋๊ณ ๋๋, ์์ผ๋ก ๋ฒจ๋ง ํฌ๋๊ฐ ํ์ํ ๋ฌธ์ ์์๋ ๋ง์๊ป ์์ฉํ ์ ์์ ๊ฒ ๊ฐ๋ค.
- ๋น๋ก ๊ทธ๋ฐ ๋ฌธ์ ์ ์๊ฐ ๋ง์ง๋ ์์ง๋ง ๐