这道题目调了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; }