#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 10000 + 10;
const int M = 50000 + 10;
int n, m;
int head1[N], tot1, head2[N], tot2;
bool vis[N];
vector<int> v; //后序访问顺序的顶点列表
int cmp[N]; //所属强连通分量的拓扑序
struct Edge
{
int v, next;
}e1[M], e2[M];
void init()
{
v.clear();
tot1 = tot2 = 0;
memset(head1, -1, sizeof(head1));
memset(head2, -1, sizeof(head2));
}
void adde(int *head, Edge *edge, int &tot, int u, int v)
{
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u)
{
vis[u] = true;
for(int i=head1[u]; i!=-1; i=e1[i].next)
{
int v = e1[i].v;
if(!vis[v]) dfs(v);
}
v.push_back(u);
}
void rdfs(int u, int k)
{
vis[u] = true;
cmp[u] = k;
for(int i=head2[u]; i!=-1; i=e2[i].next)
{
int v = e2[i].v;
if(!vis[v]) rdfs(v, k);
}
}
void disp(int *head, Edge *edge) //显示邻接表详细情况
{
for(int i=1; i<=n; i++)
{
printf("%d : ", i);
for(int j=head[i]; j!=-1; j=edge[j].next)
cout<<edge[j].v<<" ";
cout<<endl;
}
}
int SCC()//查找出有多少个强连通分量
{
memset(vis, 0, sizeof(vis));
for(int i=1; i<=n; i++)
if(!vis[i]) dfs(i);
memset(vis, 0, sizeof(vis));
int k=0;
for(int i=v.size()-1; i>=0; i--)
if(!vis[v[i]])
rdfs(v[i], k++);
return k;
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
int u, v;
init();
for(int i=0; i<m; i++)
{
scanf("%d%d", &u, &v);
adde(head1, e1, tot1, u, v); //正向图
adde(head2, e2, tot2, v, u); //反向图
}
disp(head1, e1);
cout<<endl;
disp(head2, e2);
int ans = SCC();
printf("%d\n", ans);
}
return 0;
}
/*
6 7
1 2
2 3
2 4
3 4
4 5
5 3
5 6
*/
强连通分量分解
最新推荐文章于 2022-01-14 09:51:25 发布