找出各个顶点所属的连通分量,将连通分量的点看作一个点,求这些顶点入度为0的个数和出度0的个数,取最大的即可。

1 #include<iostream> 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #define maxn 102 6 using namespace std; 7 vector<int> G[maxn],G2[maxn]; 8 vector<int> s;//栈 9 int vis[maxn], 10 sccno[maxn], //标记顶点所属的连通分量 11 scc_cnt; //记录有几个强连通分量 12 void dfs1(int u) 13 { 14 if(vis[u]) return ; //顶点遍历过则返回 15 vis[u] = 1; 16 for(int i=0; i<G[u].size(); i++)dfs1(G[u][i]); 17 s.push_back(u); //将一颗树上的顶点入栈 18 } 19 void dfs2(int u) 20 { 21 if(sccno[u])return ; 22 sccno[u] = scc_cnt; //标记顶点所属的连通分量 23 for(int i=0; i<G2[u].size(); i++)dfs2(G2[u][i]); 24 } 25 void find_scc(int n) 26 { 27 int i; 28 scc_cnt = 0; 29 s.clear(); 30 memset(sccno,0,sizeof(sccno)); 31 memset(vis,0,sizeof(vis)); 32 for(i=0; i<n; i++)dfs1(i); //对所有顶点遍历,入栈 33 for(i=n-1; i>=0; i--)if( !sccno[s[i]] ){//找强连通分量,找过了则不用找了 34 scc_cnt++; //记录找到连通分量的个数 35 dfs2(s[i]); 36 } 37 } 38 int main() 39 { 40 //freopen("in.txt","r",stdin); 41 int i,j,T,n,u,ver; 42 int in0[maxn],out0[maxn]; 43 cin>>T; 44 while(T--) 45 { 46 cin>>n; 47 for(i=1; i<=n; i++) 48 for(j=1; j<=n; j++){ 49 cin>>ver; 50 if(ver==0)break; 51 G[i-1].push_back(ver-1); //原图 52 G2[ver-1].push_back(i-1);//逆向图 53 } 54 find_scc(n); //求连通分量 55 for(i=1; i<=scc_cnt; i++)in0[i] = out0[i] = 1;//同一个连通分量所有点看成一个点 56 for(u=0; u<n; u++) 57 for(i=0; i<G[u].size(); i++){ 58 int v = G[u][i]; 59 if(sccno[i] != sccno[v]) in0[sccno[v]] = out0[sccno[u]] = 0; 60 } 61 int a = 0,b = 0; //分别统计入度和出度为0的顶点个数 62 for(i=1; i<=scc_cnt; i++){ 63 if(in0[i])a++; 64 if(out0[i])b++; 65 } 66 int ans = max(a,b); //取最大的输出 67 if(scc_cnt == 1) ans = 0; //只有一个连通分量,说明是强连通图,加0条边 68 cout<<ans<<endl; 69 for(i=0; i<=n; i++){G[i].clear();G2[i].clear();}//清空 70 } 71 return 0; 72 }