模板记录
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define x first
#define y second
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 2e5+ 10;
int dfn[N], low[N], timestamp;
int stk[N], id[N], all[N];
bool in_stk[N];
int h[N], e[N], ne[N], idx;
int n, m, top, scc_cnt;
inline void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void tarjan(int u)
{
// 记录序号以及初始化可以到达的最小标号点
dfn[u] = low[u] = ++ timestamp;
// 把当前节点放入栈内, 并且标记该节点在栈内
stk[++ top] = u, in_stk[u] = true;
// 便利当前节点的所有节点
for(int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if(!dfn[j]) // 该点未遍历
{
tarjan(j); // 便利子节点
low[u] = min(low[u], low[j]); // 更新当前节点可以到达的最小序号点
}
else if(in_stk[j])// 该点遍历过,但是在栈内,表明形成了一个回路
low[u] = min(low[u], low[j]);
}
if(dfn[u] == low[u])
{
int y;
++ scc_cnt;
do
{
y = stk[top --];
in_stk[y] = false;
id[y] = scc_cnt;
all[scc_cnt] ++;
}
while(y != u);
}
}
int du[N];
inline void sovle()
{
cin >> n >> m;
memset(h, -1, sizeof h);
for(int i = 0; i < m; i ++)
{
int a, b;
cin >> a >> b;
add(a, b);
}
for(int i = 1; i <= n; i ++)
if(!dfn[i])
tarjan(i);
for(int i = 1; i <= n; i ++)
{
for(int j = h[i]; ~j; j = ne[j])
{
int k = e[j];
if(id[i] != id[k])
du[id[i]] ++;
}
}
int s = 0;
for(int i = 1; i <= scc_cnt; i ++ )
if(du[i] == 0)
{
if(s != 0)
{
cout << "0" << endl;
return ;
}
s = i;
}
cout << all[s] << endl;
}
signed main(void)
{
IOS;
int t = 1;
// cin >> t;
while(t --) sovle();
return 0;
}
把整个图变成一个强连通块儿所需要添加的最小边数量,ans1(入度为0块儿的数量),ans2(出度为0块儿的数量),最小边数为max(ans1, ans2);
inline void sovle()
{
cin >> n;
memset(h, -1, sizeof h);
for(int i = 1; i <= n; i ++){
int a;while(cin >> a, a)add(i, a);
}
for(int i = 1; i <= n; i ++)
if(!dfn[i])
tarjan(i);
for(int i = 1; i <= n; i ++){
for(int j = h[i]; ~j; j = ne[j]){
int k = e[j];
if(id[i] != id[k]) in[id[k]] ++, out[id[i]] ++;
}
}
int ans1 = 0, ans2 = 0;
for(int i = 1; i <= scc_cnt; i ++){
if(!in[i]) ans1 ++; // 入度为0块儿的数量
if(!out[i]) ans2 ++; // 出度为0块儿的数量
}
cout << ans1 << endl;
if(scc_cnt == 1) ans1 = ans2 = 0; // 若只有一个块儿,则不需要添加边
cout << max(ans2, ans1) << endl; // 取最大值即可
}