【问题描述】
给出 n (编号为1..n)个顶点,m 条边的有向图,请完成下列任务:
任务1、计算并输出图的强连通分量数。
任务2、计算并输出图的最大强连通分量。
【输入格式】
第一行两个整数 n 表示有n个点。接下来的 n 行,第i+1行表示点i发出的有向边,其中第k个数表示i出发的第k条有向边的另一个顶点,0表示结束。
【输出格式】
第 1 行:一个整数,表示图的强连通分量数;
第 2 行:一个整数,表示图的最大强连通分量;
【输入样例】
6
2 4 0
0
2 5 0
2 5 0
1 2 0
3 5 0
【输出样例】
4
3
【数据范围】
n<=10000 m<=50000
强连通分量的求法就是正向和逆向进行bfs或dfs来找到可以互相到达的点。
具体内容如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int maxn=10005;
int n,vis[maxn],belong[maxn],se[maxn],scc=0;
vector<int>g[maxn],gr[maxn],d;
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
while(x!=0)
{
g[i].push_back(x);
gr[x].push_back(i);
scanf("%d",&x);
}
}
}
void dfs1(int i)
{
vis[i]=1;
for(int k=0;k<g[i].size();k++)
{
int j=g[i][k];
if(vis[j]) continue;
dfs1(j);
}
d.push_back(i);//记录第一次遍历的数字。
}
void dfs2(int i,int t)
{
belong[i]=t;
se[t]++;
for(int k=0;k<gr[i].size();k++)
{
int j=gr[i][k];
if(belong[j]) continue;
dfs2(j,t);
}
}
void work()
{
memset(vis,0,sizeof(vis));
memset(se,0,sizeof(se));
memset(belong,0,sizeof(belong));
for(int i=1;i<=n;i++)
if(!vis[i]) dfs1(i);//进行第一次正向遍历。
for(int i=d.size()-1;i>=0;i--)
if(!belong[d[i]]) dfs2(d[i],++scc);//第二次dfs要后序遍历来进行,才能避免一些错误的发生。
}
int main()
{
init();
work();
printf("%d\n",scc);
int ans=0;
for(int i=1;i<=scc;i++)
ans=max(ans,se[i]);
printf("%d\n",ans);
return 0;
}