https://www.acmicpc.net/problem/4013
4013번: ATM
첫째 줄에 교차로의 수와 도로의 수를 나타내는 2개의 정수 N과 M(N, M ≤ 500,000)이 차례로 주어진다. 교차로는 1부터 N까지 번호로 표시된다. 그 다음 M개의 줄에는 각 줄마다 각 도로의 시작 교차
www.acmicpc.net
[문제]
[풀이]
어우 .. 어질어질하다..
SCC 활용 DP 문제이긴 한데 , 처음에 SCC 집단들을 구해서 indegree가 0인거부터 진행했는데 왜 안되지..? 했다가
나중에 알고보니 start 지점이 정해져있다는 걸 뒤늦게 알았고 한참을 헤맸다 ..
접근방법
1. SCC집단을 구할 것.
2. SCC집단마다 번호를 매기고 , 이 자체를 하나의 Node로 취급하여 또 다른 totalATM을 만들어서 atm의 합을 구함.
3. start 지점의 SCC부터 탐색을 진행해서 totalATM을 더해나가는 DP를 갱신시킴
4. SCC 지점이 레스토랑이면 DP 값들 중 최대값을 구해서 리턴
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
105
106
107
108
109
110
111
112
|
import java.util.*;
import java.io.*;
import java.util.stream.*;
public class Main {
static boolean[] finished,isRes;
static int n, m, index, sccIndex, start, max;
static int[] discover,sccNum,atm,totalAtm,dp;
static ArrayList<ArrayList<Integer>> list,sccList;
static Stack<Integer> st;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] input = br.readLine().split(" ");
n = Integer.parseInt(input[0]);
m = Integer.parseInt(input[1]);
list = new ArrayList<>();
atm = new int[n+1];
for (int i = 0; i <= n; i++) list.add(new ArrayList<>());
for (int i = 0; i < m; i++) {
int[] edge = Arrays.stream(br.readLine().split(" "))
.mapToInt(Integer::parseInt).toArray();
list.get(edge[0]).add(edge[1]);
}
for(int i=1;i<=n;i++) atm[i] = Integer.parseInt(br.readLine());
input = br.readLine().split(" ");
start = Integer.parseInt(input[0]);
isRes = new boolean[n+1];
Arrays.stream(br.readLine().split(" "))
.mapToInt(Integer::parseInt).forEach(e->isRes[e]=true);
findScc();
setSccInfo();
sccBfs();
for(int i=1;i<=n;i++)
if(isRes[i]) max = Math.max(max,dp[sccNum[i]]);
System.out.println(max);
}
private static void sccBfs() {
LinkedList<Integer> q = new LinkedList<>();
q.add(sccNum[start]);
dp[sccNum[start]] = totalAtm[sccNum[start]];
while (!q.isEmpty()){
Integer cur = q.poll();
for (Integer next : sccList.get(cur)) {
if(dp[next] < dp[cur] + totalAtm[next]){
dp[next] = dp[cur]+totalAtm[next];
q.add(next);
}
}
}
}
private static void setSccInfo() {
totalAtm = new int[sccIndex+1];
sccList = new ArrayList<>();
dp = new int[sccIndex+1];
for(int i=0;i<=sccIndex;i++) sccList.add(new ArrayList<>());
for (int i = 1; i <= n; i++) {
totalAtm[sccNum[i]]+=atm[i];
for (Integer next : list.get(i))
if (sccNum[i] != sccNum[next]) sccList.get(sccNum[i]).add(sccNum[next]);
}
}
private static void findScc() {
index = 0;
discover = new int[n + 1];
finished = new boolean[n + 1];
st = new Stack<>();
sccIndex = 0;
sccNum = new int[n + 1];
for (int i = 1; i <= n; i++)
if (discover[i] == 0) dfs(i);
}
private static int dfs(int cur) {
discover[cur] = ++index;
st.push(cur);
int parent = discover[cur];
for (Integer next : list.get(cur)) {
if (discover[next] == 0) parent = Math.min(dfs(next), parent);
else if (!finished[next]) parent = Math.min(discover[next], parent);
}
if (parent == discover[cur]) {
while (true) {
Integer pop = st.pop();
finished[pop] = true;
sccNum[pop] = sccIndex + 1;
if (pop == cur) break;
}
sccIndex++;
}
return parent;
}
}
|
cs |
'알고리즘,PS > 백준' 카테고리의 다른 글
[BOJ] 백준 [2109] 순회강연 JAVA (0) | 2021.11.25 |
---|---|
[BOJ] 백준 [3977] 축구전술 JAVA (0) | 2021.11.25 |
[BOJ] 백준 [4196] 도미노 JAVA (0) | 2021.11.23 |
[BOJ] 백준 [1948] 임계경로 JAVA (0) | 2021.11.21 |
[BOJ] 백준 [2957] 이진탐색트리 JAVA (0) | 2021.11.11 |