2014-10-14 02:19:23
思路:大白书的例题,挺好的强连通分量入门题。问题的大意就是问最少添加几条边能使一个有向图强连通。做法是,先求一遍强连通分量,然后把每个强连通分量缩点,这样实际上就形成了DAG,接下来只要判断每个缩点的入度和出度,找出入度为0的点个数a1,出度为0的点个数a2,然后取a1和a2的最大值,即是答案。(因为最终要使得每个缩点的入度、出度不为零,而添加一条边可以减少a1,也不可以不减少a1;可以减少a2,也可以不减少a2,那么最小答案就是max(a1,a2))
1 /************************************************************************* 2 > File Name: 2767.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Tue 14 Oct 2014 12:54:49 AM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 const int maxn = 20010; 27 28 int first[maxn],next[maxn * 3],ver[maxn * 3],ecnt; 29 int dfn[maxn],low[maxn],sc[maxn],tot,scnt,din[maxn],dout[maxn]; 30 int n,m,T; 31 stack<int> S; 32 33 void Add_edge(int u,int v){ 34 next[++ecnt] = first[u]; 35 ver[ecnt] = v; 36 first[u] = ecnt; 37 } 38 39 void Dfs(int p){ 40 dfn[p] = low[p] = ++tot; 41 S.push(p); 42 for(int i = first[p]; i != -1; i = next[i]){ 43 int v = ver[i]; 44 if(!dfn[v]){ 45 Dfs(v); 46 low[p] = min(low[p],low[v]); 47 } 48 else if(!sc[v]){ 49 low[p] = min(low[p],dfn[v]); 50 } 51 } 52 if(low[p] == dfn[p]){ 53 ++scnt; 54 while(1){ 55 int x = S.top(); 56 S.pop(); 57 sc[x] = scnt; 58 if(x == p) break; 59 } 60 } 61 } 62 63 void Tarjan(){ 64 memset(dfn,0,sizeof(dfn)); 65 memset(low,0,sizeof(low)); 66 memset(sc,0,sizeof(sc)); 67 while(!S.empty()) S.pop(); 68 for(int i = 1; i <= n; ++i) 69 if(!dfn[i]) Dfs(i); 70 } 71 72 void Init(){ 73 memset(first,-1,sizeof(first)); 74 memset(din,0,sizeof(din)); 75 memset(dout,0,sizeof(dout)); 76 ecnt = tot = scnt = 0; 77 } 78 79 int main(){ 80 int a,b; 81 scanf("%d",&T); 82 while(T--){ 83 Init(); 84 scanf("%d%d",&n,&m); 85 for(int i = 1; i <= m; ++i){ 86 scanf("%d%d",&a,&b); 87 Add_edge(a,b); 88 } 89 Tarjan(); 90 if(scnt == 1){ 91 printf("0\n"); 92 continue; 93 } 94 for(int k = 1; k <= n; ++k){ 95 for(int i = first[k]; i != -1; i = next[i]){ 96 int v = ver[i]; 97 if(sc[k] != sc[v]){ 98 dout[sc[k]]++; 99 din[sc[v]]++; 100 } 101 } 102 } 103 int c1,c2; 104 c1 = c2 = 0; 105 for(int i = 1; i <= scnt; ++i){ 106 if(dout[i] == 0) ++c1; 107 if(din[i] == 0) ++c2; 108 } 109 printf("%d\n",max(c1,c2)); 110 } 111 return 0; 112 }