这道题目调了n久,最后终于攻克了,赞一个
图论题目,模板要高度可靠
题意抽象:
要完成两个任务
1:最少从几个点开始遍历就能遍历所有的点,即求缩点后入度为零的点的个数
如果不缩点,举个例子:有两个环,没有点入度为0,但是还是需要分别从两个环中的点开始遍历,所以要先缩点
2、最少需要连几条边,图就变成强连通了,即把入度为0 和出度为0的点都连起来,相当于把一棵树的叶子和根连起来,最少需要连的边数为出度为0的连通块数的入度为0的连通块数的较大值(应该很容易想的)
另外,需要注意一个地方,就是原图可能就是强连通,缩点后就只有一个点了,入度出度均为0,所以要特判一下
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
const int MAX = 10010;
vector<int> edge[MAX];
int st[MAX];
int dfn[MAX],low[MAX];
int top,btype,tdfn;
int belong[MAX];
bool ins[MAX];
void dfs(int s)
{
int i,t;
dfn[s]=low[s]=++tdfn;
ins[s]=true;
st[++top]=s;
for(i=0;i<edge[s].size();i++)
{
t=edge[s][i];
if(!dfn[t])
{
dfs(t);
if(low[t]<low[s]) low[s]=low[t];
}
else if(ins[t] && dfn[t]<low[s]) low[s]=dfn[t];
}
if(dfn[s]==low[s])
{
btype++;
do
{
t=st[top--];
ins[t]=false;
belong[t]=btype;
}while(t!=s);
}
}
void SCC(int n)
{
int i;
top=btype=tdfn=0;
memset(ins,false,sizeof(ins));
memset(dfn,0,sizeof(dfn));
for(i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
}
int chu[MAX];
int in[MAX];
int main()
{
int i,j,a,n;
int A_ans,B_ans;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<=n;i++)
edge[i].clear();
for(i=1;i<=n;i++)
{
while(scanf("%d",&a),a)
{
edge[i].push_back(a);
}
}
if(n==1) {printf("1\n0\n");continue;}
SCC(n);
if(btype==1) {printf("1\n0\n");continue;}
memset(chu,0,sizeof(chu));
memset(in,0,sizeof(in));
for(i=1;i<=n;i++)
{
int tmp=belong[i];
for(j=0;j<edge[i].size();j++)
{
int tmp1=belong[edge[i][j]];
if(belong[i]!=belong[edge[i][j]])
{
chu[tmp]++;
in[tmp1]++;
}
}
}
A_ans=B_ans=0;
for(i=1;i<=btype;i++)
{
if(chu[i]==0) B_ans++;
if(in[i]==0) A_ans++;
}
B_ans=A_ans>B_ans?A_ans:B_ans;
printf("%d\n%d\n",A_ans,B_ans);
}
return 0;
}