B3609 [图论与代数结构 701] 强连通分量(强连通分量)
B3609 [图论与代数结构 701] 强连通分量
题目描述
给定一张 \(n\) 个点 \(m\) 条边的有向图,求出其所有的强连通分量。
注意,本题可能存在重边和自环。
输入格式
第一行两个正整数 \(n\) , \(m\) ,表示图的点数和边数。
接下来 \(m\) 行,每行两个正整数 \(u\) 和 \(v\) 表示一条边。
输出格式
第一行一个整数表示这张图的强连通分量数目。
接下来每行输出一个强连通分量。第一行输出 1 号点所在强连通分量,第二行输出 2 号点所在强连通分量,若已被输出,则改为输出 3 号点所在强连通分量,以此类推。每个强连通分量按节点编号大小输出。
输入输出样例 #1
输入 #1
6 8
1 2
1 5
2 6
5 6
6 1
5 3
6 4
3 4
输出 #1
3
1 2 5 6
3
4
说明/提示
对于所有数据,\(1 \le n \le 10000\),\(1 \le m \le 100000\)。
这道题是一道标准的强连通分量的题,但我还是卡了好久,首先对于自环我们只需要判断a1=b就行了,对于重边,我用的是set容器,然后在出栈的时候我们需要存储每个点在第几个强连通分量当中,然后在遍历的过程中,如果改点所对应的强连通分量已经输出了,说明该点就已经输出了,此时我们直接跳过就行
#include<iostream>
#include<vector>
#include<stack>
#include<set>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int n,m,a,b;
int low[N],dfsn[N],vis[N];
set<int>v[N];
vector<int>ans[N];
int vis1[N];
int vis2[N];
stack<int>s;
int t=0,cnt=0;
void dfs(int x){
low[x]=dfsn[x]=++t;
vis[x]=1;
s.push(x);
for(auto i=v[x].begin();i!=v[x].end();i++){
int y=*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]){
++cnt;
while(s.top()!=x){
ans[cnt].push_back(s.top());
vis1[s.top()]=cnt;
vis[s.top()]=0;
s.pop();
}
ans[cnt].push_back(s.top());
vis1[s.top()]=cnt;
vis[s.top()]=0;
s.pop();
}
}
int main(){
cin>>n>>m;
while(m--){
cin>>a>>b;
if(a!=b)v[a].insert(b);
}
for(int i=1;i<=n;i++)if(!dfsn[i])dfs(i);
cout<<cnt;
cout<<endl;
for(int i=1;i<=n;i++){
int w=vis1[i];
if(vis2[w])continue;
vis2[w]=1;
sort(ans[w].begin(),ans[w].end());
for(int j=0;j<ans[w].size();j++)cout<<ans[w][j]<<" ";
cout<<endl;
}
return 0;
}

浙公网安备 33010602011771号