https://www.luogu.com.cn/problem/P2863
[USACO06JAN] The Cow Prom S
题目描述
有一个 n 个点,m 条边的有向图,请求出这个图点数大于 1 的强连通分量个数。
输入格式
第一行为两个整数 n 和 m。
第二行至 m+1 行,每一行有两个整数 a 和 b,表示有一条从 a 到 b 的有向边。
输出格式
仅一行,表示点数大于 1 的强连通分量个数。
样例 #1
样例输入 #1
5 4
2 4
3 5
1 2
4 1
样例输出 #1
1
思路
先利用tarjan进行缩点,然后循环判断siz[i]的个数是否大于1,时间复杂度为O(n+m);
代码
#include<bits/stdc++.h>
#pragma G++ optimize(2)
#pragma G++ optimize("inline")
using namespace std;
const int p=10004;
int n,m,dfn[p],low[p],tot,scc[p],siz[p];
int cnt,stk[p],top,u,v,sum;
bool f[p];
vector<int>w[p];
void tarjan(int x){
dfn[x]=low[x]=++tot;
stk[++top]=x,f[x]=1;
for(auto i:w[x]){
if(!dfn[i]){
tarjan(i);
low[x]=min(low[x],low[i]);
}else if(f[i]){
low[x]=min(low[x],dfn[i]);
}
}
if(dfn[x]==low[x]){
int i;
++cnt;
do{
i=stk[top--],f[i]=0;
scc[i]=cnt,++siz[cnt];
}while(i!=x);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>v;
w[u].push_back(v);
}
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i);
}
}
for(int i=1;i<=cnt;i++){
if(siz[i]>1){
sum++;
}
}
cout<<sum;
return 0;
}
标签:cnt,Cow,int,tarjan,P2863,++,Prom,dfn,low
From: https://www.cnblogs.com/zyc231254/p/18589556