洛谷P2746

第一问应该转化为求入度为0的点个数

第二问取入度为0的点个数与出度为0的点个数的较大值,注意特判仅有一个强连通分量的情况。

参考:题解 P2746 【[USACO5.3]校园网Network of Schools】


首先用Kosaraju求出各个强连通分量缩点,然后求出各个强连通分量间的有向边。
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
const int N = 186;
int n, cnt,mark[N],c,r;
vi v[N], rv[N], dfn, scc[N];
set<int> s[N], rs[N];
bitset<200> vis;

void dfs(int x)
{
vis[x] = 1;
for (auto it : v[x])
{
if (!vis[it])
dfs(it);
}
dfn.pb(x);
}

void dfs1(int x)
{
scc[cnt].pb(x);
mark[x] = cnt;
for (auto it : rv[x])
{
if (!mark[it])
dfs1(it);
}
}


int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
f(i, 1, n)
{
int x;
cin >> x;
while (x)
{
v[i].pb(x);
rv[x].pb(i);
cin >> x;
}
}
vis.reset();
f(i, 1, n)
{
if (!vis[i])
{
dfs(i);
}
}
for (auto it = dfn.rbegin(); it != dfn.rend(); it++)
{
if (!mark[*it])
{
cnt += 1;
dfs1(*it);
}
}
f(i, 1, n)
{
for (auto it : v[i])
{
if(mark[i]!=mark[it]){
s[mark[i]].insert(mark[it]);
}
}
for (auto it : rv[i])
{
if(mark[i]!=mark[it]){
rs[mark[i]].insert(mark[it]);
}
}
}
f(i,1,cnt){
if(!s[i].size())c+=1;
if(!rs[i].size())r+=1;
}
cout<<r<<"\n"<<(cnt==1?0:max(c,r));
return 0;
}