P2863 [USACO06JAN] The Cow Prom S
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
说明/提示
数据规模与约定
对于全部的测试点,保证 \(2\le n \le 10^4\),\(2\le m\le 5\times 10^4\),\(1 \leq a, b \leq n\)。
首先我犯了两个错误,第一就是在点弹出栈的时候没有将它的vis数组标记为0;
第二就是,寻找连通量时直接从第一个节点遍历,但第一个点是孤立的,无法拓展到其他点,所以应当遍历每一个点,如果它没有在其他点遍历的时候被遍历到,就让他进dfs函数
#include<iostream>
#include<vector>
#include<stack>
#define int long long
using namespace std;
const int N=1e5+5;
vector<int>v[N];
int vis[N];
int dfsn[N];
int low[N];
int t=0;
stack<int>s;
int ans=0;
void dfs(int x){
dfsn[x]=low[x]=++t;
s.push(x);
vis[x]=1;
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
if(!dfsn[y]){
dfs(y);
low[x]=min(low[x],low[y]);
}
else if(vis[y])low[x]=min(low[x],dfsn[y]);
}
if(low[x]==dfsn[x]){
int cnt=0;
while(s.top()!=x){
vis[s.top()]=0;
s.pop();
cnt++;
}
vis[s.top()]=0;
s.pop();
cnt++;
if(cnt>1)ans++;
}
}
signed main(){
int n,m;
cin>>n>>m;
while(m--){
int a,b;
cin>>a>>b;
v[a].push_back(b);
}
for(int i=1;i<=n;i++)if(!dfsn[i])dfs(i);
cout<<ans;
return 0;
}

浙公网安备 33010602011771号