铁丝网

互相联通的梦境

0%

tarjan找强连通分量

今天说一说找强连通分量的tarjan算法

这篇真的很好,我就是靠这个真正明白的。

例题:

代码:

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
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m;
const int N = 100005;
struct Edge
{
int v,next;
}e[N*2],e1[N*2];
int front[N],cnt = 0,val[N],co[N],stk[N],dfn[N],low[N],f[N],vl[N];
bool instk[N];
int cnt1 = 0, front1[N],tot = 0;
int tp = 0, t = 0;
void AddEdge(int u,int v)
{
e[++cnt].v = v;
e[cnt].next = front[u];
front[u] = cnt;
}
void AddEdge1(int u,int v)
{
e1[++cnt1].v = v;
e1[cnt1].next = front1[u];
front1[u] = cnt1;
}
void tarjan(int now)
{
dfn[now] = low[now] = ++t;
instk[now] = true;
stk[++tp] = now;
for (int i = front[now]; i; i = e[i].next)
{
int xx = e[i].v;
if(!dfn[xx])
{
tarjan(xx);
low[now] = min(low[now],low[xx]);
}
else if (instk[xx])
{
low[now] = min(low[now],dfn[xx]);
}
}
if(dfn[now] == low[now])
{
tot++;
vl[tot] = 0;
while(stk[tp+1] != now)
{
int xx = stk[tp];
vl[tot] += val[xx];
tp--;
instk[xx] = false;
co[xx] = tot;
}
}
}
void search(int x)
{
if(f[x]) return;
f[x] = vl[x];
int maxs = 0;
for (int i = front1[x]; i; i = e1[i].next)
{
int xx = e1[i].v;
if(!f[xx]) search(xx);
maxs = max(maxs, f[xx]);
}
f[x] += maxs;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i++) scanf("%d",&val[i]);
for (int i = 1; i <= m; i++)
{
int a,b;
scanf("%d%d",&a,&b);
AddEdge(a,b);
}
for (int i = 1; i <= n; i++)
{
if (!dfn[i]) tarjan(i);
}
for (int k = 1; k <= n; k++)
{
for (int i = front[k]; i; i = e[i].next)
{
int xx = e[i].v;
if(co[xx] != co[k]) AddEdge1(co[k],co[xx]);
}
}
// cout<<tot<<endl;
int cur,res = 0;
memset(f,0,sizeof f);
for (int k = 1; k <= tot; k++)
{
//cout<< vl[k] <<endl;
//cout<<vl[k]<<endl;
if (!f[k]) search(k);
// cout<< k <<" "<<f[k]<<endl;
res = max(res, f[k]);
}
printf("%d\n", res);
return 0;
}

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include<iostream>
#include<cstdio>
#include<utility>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 10005;
int n,p,r;
struct Edge
{
int v,next;
}e[N],e1[N];

int cnt = 0, cnt1 = 0;
int front[N],front1[N];
int val[N],vl[N];
int stk[N],dfn[N],low[N],co[N],num[N],rudu[N];
int tot = 0, t = 0, tp = 0;
bool instk[N],vis[N];
int inf;
pair<int,int> node[N];

void AddEdge(int u,int v)
{
e[++cnt].v = v;
e[cnt].next = front[u];
front[u] = cnt;
}
void AddEdge1(int u,int v)
{
e1[++cnt1].v = v;
e1[cnt1].next = front1[u];
front1[u] = cnt1;
}

void tarjan(int now)
{
dfn[now] = low[now] = ++t;
instk[now] = true;
stk[++tp] = now;
for (int i = front[now]; i; i = e[i].next)
{
int xx = e[i].v;
if (!dfn[xx])
{
tarjan(xx);
low[now] = min(low[now],low[xx]);
}
else if(instk[xx])
{
low[now] = min(low[now],dfn[xx]);
}
}
if(dfn[now] == low[now])
{
tot++;
while(stk[tp + 1] != now)
{
int xx = stk[tp];
tp--;
instk[xx] = false;
co[xx] = tot;
num[tot] = min(num[tot],xx);
vl[tot] = min(vl[tot],val[xx]);
}
}
}
bool cmp(pair<int,int> a, pair<int,int> b)
{
return a.second < b.second;
}
int main()
{
scanf("%d%d",&n,&p);
memset(val,127,sizeof val);
memset(vl,127,sizeof vl);
memset(num,127,sizeof num);
for (int i = 1; i <= p; i++)
{
int t = 0;
scanf("%d",&t);
scanf("%d",&val[t]);
}
scanf("%d",&r);
for (int i = 1; i <= r; i++)
{
int a,b;
scanf("%d%d",&a,&b);
AddEdge(a,b);
}

inf = vl[1];
for (int i = 1; i <= n; i++)
{
if (!dfn[i]) tarjan(i);
}
for (int k = 1; k <= n; k++)
{
for (int i = front[k]; i; i = e[i].next)
{
int xx = e[i].v;
if(co[k] != co[xx])
{
// cout<<num[co[k]]<<"-->"<<num[co[xx]]<<endl;
AddEdge1(co[k],co[xx]);
rudu[co[xx]]++;
}
}
}
int res = 0;
bool flg = false;
for (int i = 1; i <= tot; i++)
{
// cout<<num[i]<<" "<<rudu[i]<<" "<<vl[i]<<endl;
if (rudu[i] == 0 && vl[i] != inf)
{
res += vl[i];
vis[i] = true;
for (int j = front1[i]; j; j = e1[j].next)
{
int xx = e1[j].v;
vis[xx] = true;
}
}
else if (rudu[i] == 0 && vl[i] == inf) {
// cout<< "NO_i "<<i<<endl;
flg = true;
}
}
int foo = inf;
if(!flg) printf("YES\n%d",res);
else
{
for (int i = 1; i <= tot; i++)
{
if (rudu[i] == 0 && vl[i] == inf)
{
foo = min(foo,num[i]);
for (int j = front1[i]; j; j = e[j].next)
{
int xx = e[j].v;
if(vis[xx]) continue;
else foo = min(foo,num[xx]);
}
}
}
printf("NO\n%d",foo);
}
return 0;
}