正题
POJ题目链接
给出一个图,求联通块数量和加入多少条边后会将全图变为一个最强联通块。
机翻输入输出(需要自取)
输入
第一行包含整数N:网络中的学校数量(2 <= N <= 100)。学校由前N个正整数标识。接下来的N行中的每一行都描述了一个接收者列表。第i + 1行包含学校i的接收者的标识符。每个列表以0结尾。空列表在行中仅包含一个0。
输出
你的程序应该写两行到标准输出。第一行应包含一个正整数:子任务A的解决方案。第二行应包含子任务B的解决方案。
示例输入
5
2 4 3 0
4 5 0
0
0
1 0
示例输出
1
2
解题思路
- 先跑一边Kosaraju算法。那么我们可以得出每一个学校在哪一个强连通分量里。然后算出入度为0 的强连通分量的个数。就是第一个答案。
- 读为0的强连通分量的那些强连通分量连起来。所以算出出度为0和入度为0的最大值,就是第二个的答案。
- 注意如果强连通分量的个数是一个,那么第二个的答案是0.
代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,out[201],w,s,s1,lt[201],s2,in[201];
bool v[201],a[201][201];
int dfs(int x)
{v[x]=true;for (int i=1;i<=n;i++){if (a[x][i] && !v[i]){dfs(i);}}out[++w]=x;
}
void dfs2(int x)
{v[x]=true;lt[x]=s;for (int i=1;i<=n;i++){if (a[i][x] && !v[i]){dfs2(i);}}
}//求强连通分量
int main()
{scanf("%d",&n);for (int i=1;i<=n;i++){while (true){int x;scanf("%d",&x);if (x==0) break;a[i][x]=true;}}for (int i=1;i<=n;i++){if (!v[i]){dfs(i);}}memset(v,false,sizeof(v));for (int i=n;i>=1;i--){if (!v[out[i]]){s++;dfs2(out[i]);}}memset(out,0,sizeof(out));for (int i=1;i<=n;i++)for (int j=1;j<=n;j++)if (a[i][j] && lt[i]!=lt[j]){out[lt[i]]++;in[lt[j]]++;//统计每个联通块的出度入度}for (int i=1;i<=s;i++){if (in[i]==0) s1++;if (out[i]==0) s2++;//统计为0的个数}if (s==1) printf("1\n0");//特判else printf("%d\n%d",s1,max(s1,s2));//输出
}