오답 노트 & 새로 알게 된 점
해당 문제는 풀이 방법이 두 가지 있다.
첫 번째 방법은 생각하기 쉽지만 시간 복잡도가 다른 방법에 비해 크고,
다른 방법은 와 이걸 이렇게도 풀구나 하면서(나만 그럴 수 있음) 시간 복잡도가 첫 번째 방법에 비해 작다.
첫 번째 풀이
일반적으로 다익스트라를 사용한다.
다만 문제에서 출발할 때의 최소 경로 + 복귀할 때의 최소 경로 중 최댓값을 구하라했다.
일반적으로 나는 이와 같은 문제를 풀 때 다익스트라를 모든 정점에서 구한다(N번)
예제에서 start가 1, 3, 4 (2는 파티정점이므로 제외) 일 때 다익스트라를 구하여 각각 dist[X] 값을 더해주고,
또 start가 2일 때 다익스트라를 구하여 각각 dist[N] 을 더해주었다. 그리고 이 중에 최댓값을 구해줬다.
해당 풀이는 시간 복잡도가 N^2logN으로 아래와 같은 시간이 나왔다.
두 번째 풀이
두 번째 풀이는 정말 신기했다.
처음 풀이보다 시간 복잡도가 3배나 줄게 된다.
예제를 그림으로 표현하면 복귀 부분이다.
하지만 입력에서 반대로 가는 경로도 저장해준다.
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int from = atoi(st.nextToken());
int to = atoi(st.nextToken());
int wei = atoi(st.nextToken());
A[from].add(new Node(to, wei));
B[to].add(new Node(from, wei));
}
이렇게 되면 파티하는 정점에서의 다익스트라를 구하게 되면 출발, 복귀하는 최소 경로를 NlogN에 찾을 수 있다.
즉, 1번 풀이에서는 다익스트라를 N번 반복했지만, 해당 풀이는 2번의 다익스트라를 실행하면 된다.
어떻게 이렇게 풀 수 있을까?
우리가 구해야할 것은
1. 각 정점마다 X까지의 최소경로
2. X에서 출발하여 각 정점까지의 최소경로이다.
다익스트라는 한 정점에서 모든 정점까지의 최소 경로를 구하는 알고리즘이다.
2번은 우리가 일반적으로 풀었던 다익스트라로 풀면 금방 구한다.
1번 풀이는 다익스트라를 N번 돌려야 알 수 있는 값이다.
( 1번에서 다익 구한 뒤 dist[X], 2번에서 다익 구한 뒤 dist[X] ...)
하지만 문제에서 단방향이라고 했으므로 문제에서 주어진 from과 to를 바꿔서 X에서 출발한다고 생각한다.
X를 출발점으로 하고 각 정점의 최소경로를 구하면 한 번에 구해지는 것을 알 수 있다.
코드 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
import java.io.*;
import java.util.*;
public class Main {
static int atoi(String str) {
return Integer.parseInt(str);
}
static int N, M, X;
static ArrayList<Node> A[];
static int dist[];
static int ans[];
public static void main(String[] args) throws IOException {
input();
pro();
}
static void pro() {
for (int i = 1; i <= N; i++) {
if(i == X) continue;
dijkstra(i);
ans[i] += dist[X];
}
dijkstra(X);
for (int i = 1; i <= N; i++) {
if(i == X) continue;
ans[i] += dist[i];
}
int max = Integer.MIN_VALUE;
for (int i = 1; i <= N; i++) {
max = Math.max(max, ans[i]);
}
System.out.println(max);
}
static void dijkstra(int start) {
Arrays.fill(dist, Integer.MAX_VALUE);
PriorityQueue<Info> pq = new PriorityQueue<>((o1, o2)->{
return o1.dist - o2.dist;
});
pq.offer(new Info(start, 0));
dist[start] = 0;
while (!pq.isEmpty()) {
Info info = pq.poll();
for (Node n : A[info.idx]) {
if(dist[info.idx] != info.dist) continue;
if(dist[info.idx] + n.wei >= dist[n.to]) continue;
dist[n.to] = dist[info.idx] + n.wei;
pq.offer(new Info(n.to, dist[n.to]));
}
}
}
static void input() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = atoi(st.nextToken());
M = atoi(st.nextToken());
X = atoi(st.nextToken());
A = new ArrayList[N + 1];
dist = new int[N + 1];
ans = new int[N + 1];
for (int i = 0; i <= N; i++) A[i] = new ArrayList<>();
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int from = atoi(st.nextToken());
int to = atoi(st.nextToken());
int wei = atoi(st.nextToken());
A[from].add(new Node(to, wei));
}
}
static class Node{
int to, wei;
public Node(int to, int wei) {
this.to = to;
this.wei = wei;
}
}
static class Info{
int idx, dist;
public Info(int idx, int dist) {
this.idx = idx;
this.dist = dist;
}
}
}
|
cs |
코드 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
import java.io.*;
import java.util.*;
public class Main {
static int atoi(String str) {
return Integer.parseInt(str);
}
static int N, M, X;
static ArrayList<Node> A[];
static ArrayList<Node> B[];
static int dist1[];
static int dist2[];
public static void main(String[] args) throws IOException {
input();
pro();
}
static void pro() {
dijkstra(X, dist1, A);
dijkstra(X, dist2, B);
int max = Integer.MIN_VALUE;
for (int i = 1; i <= N; i++) {
max = Math.max(max, dist1[i] + dist2[i]);
}
System.out.println(max);
}
static void dijkstra(int start, int d[], ArrayList<Node> al[]) {
Arrays.fill(d, Integer.MAX_VALUE);
PriorityQueue<Info> pq = new PriorityQueue<>((o1, o2)->{
return o1.dist - o2.dist;
});
pq.offer(new Info(start, 0));
d[start] = 0;
while (!pq.isEmpty()) {
Info info = pq.poll();
for (Node n : al[info.idx]) {
if(d[info.idx] != info.dist) continue;
if(d[info.idx] + n.wei >= d[n.to]) continue;
d[n.to] = d[info.idx] + n.wei;
pq.offer(new Info(n.to, d[n.to]));
}
}
}
static void input() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = atoi(st.nextToken());
M = atoi(st.nextToken());
X = atoi(st.nextToken());
A = new ArrayList[N + 1];
B = new ArrayList[N + 1];
dist1 = new int[N + 1];
dist2 = new int[N + 1];
for (int i = 0; i <= N; i++){
A[i] = new ArrayList<>();
B[i] = new ArrayList<>();
}
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int from = atoi(st.nextToken());
int to = atoi(st.nextToken());
int wei = atoi(st.nextToken());
A[from].add(new Node(to, wei));
B[to].add(new Node(from, wei));
}
}
static class Node{
int to, wei;
public Node(int to, int wei) {
this.to = to;
this.wei = wei;
}
}
static class Info{
int idx, dist;
public Info(int idx, int dist) {
this.idx = idx;
this.dist = dist;
}
}
}
|
cs |
'BOJ(Java)' 카테고리의 다른 글
자바(백준) 1520 내리막 길 (0) | 2022.01.09 |
---|---|
자바(백준) 16637 괄호 추가하기 (0) | 2022.01.02 |
자바(백준) 1719 택배 (0) | 2021.12.28 |
자바(백준) 1261 알고스팟 (0) | 2021.12.28 |
자바(백준) 23629 이 얼마나 끔찍하고 무시무시한 수식이니 (0) | 2021.12.27 |