题目大意: 给定一个n (n<=100)个点的有向图,
问:Q1、最少需要选择多少个点,使得从这些点出发能遍历完整个图;
Q2、最少需要添加多少条有向边,使得整个图成为强连通图;
分析:
求出强连通分量后进行缩点,得到每个强连通分量的入度in[],出度out[];
Q1: 入度为0的强连通分量个数; Q2: max( 入度为0的强连通分量个数 , 出度为0的强连通分量个数 );
注意的地方:假如原图就是一个强连通图。则显然Q2是0.
kosaraju:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 // File Name: 1236.cpp 2 // Author: Missa 3 // Created Time: 2013/2/6 星期三 19:44:12 4 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 #include<algorithm> 9 #include<cmath> 10 #include<queue> 11 #include<stack> 12 #include<string> 13 #include<vector> 14 #include<cstdlib> 15 #include<map> 16 using namespace std; 17 18 const int maxn = 1e2+5; 19 int n; 20 vector<int>adj[maxn]; 21 vector<int>radj[maxn]; 22 vector<int>ord; 23 bool vis[maxn]; 24 int ma[maxn]; 25 int cnt; 26 void init() 27 { 28 for(int i=0;i<maxn;i++) 29 { 30 adj[i].clear(); 31 radj[i].clear(); 32 } 33 ord.clear(); 34 cnt=0; 35 } 36 void dfs1(int v) 37 { 38 vis[v]=1; 39 for(int i=0;i<adj[v].size();i++) 40 if(!vis[adj[v][i]]) 41 dfs1(adj[v][i]); 42 ord.push_back(v); 43 } 44 void dfs2(int v) 45 { 46 vis[v]=1; 47 ma[v]=cnt; 48 for(int i=0;i<radj[v].size();i++) 49 if(!vis[radj[v][i]]) 50 dfs2(radj[v][i]); 51 } 52 void kosaraju() 53 { 54 memset(vis,0,sizeof(vis)); 55 ord.clear(); 56 for(int i=1;i<=n;i++) 57 if(!vis[i]) 58 dfs1(i); 59 memset(vis,0,sizeof(vis)); 60 cnt=0; 61 for(int i=ord.size()-1;i>=0;i--) 62 { 63 if(!vis[ord[i]]) 64 { 65 cnt++; 66 dfs2(ord[i]); 67 } 68 } 69 } 70 void read() 71 { 72 for(int i=1;i<=n;i++) 73 { 74 int x; 75 while(scanf("%d",&x)) 76 { 77 if(x==0) break; 78 adj[i].push_back(x); 79 radj[x].push_back(i); 80 } 81 } 82 } 83 void solve() 84 { 85 int ans1=0,ans2=0; 86 int in[maxn],out[maxn];//入度,出度 87 memset(in,0,sizeof(in)); 88 memset(out,0,sizeof(out)); 89 for(int i=1;i<=n;i++) 90 { 91 for(int j=0;j<adj[i].size();j++) 92 { 93 int tt=adj[i][j]; 94 if(ma[i]==ma[tt]) continue; 95 out[ma[i]]++; 96 in[ma[tt]]++; 97 } 98 } 99 for(int i=1;i<=cnt;i++) 100 { 101 if(in[i]==0) ans1++; 102 if(out[i]==0) ans2++; 103 } 104 printf("%d\n",ans1); 105 if(cnt==1)//原图是一个强连通分量 106 printf("0\n"); 107 else 108 printf("%d\n",max(ans1,ans2)); 109 } 110 int main() 111 { 112 while(~scanf("%d",&n)) 113 { 114 init(); 115 read(); 116 kosaraju(); 117 solve(); 118 } 119 return 0; 120 }