1 /************************************************* 2 Proving Equivalences(hdu 2767) 3 强连通入门题 4 给个有向图,求至少加多少条边使得图是所有点都是强连通的 5 由a->b->c->a易知n个点至少要n条边,每个出度和入度都要大 6 于1。先求所有所有强连通分量,把每个强连通分量看成一个点 7 在找每个点的出度和入度,最后还差的出度和入度的最大值就是 8 答案。 9 10 *************************************************/ 11 12 13 #include<cstdio> 14 #include<iostream> 15 #include<cstring> 16 #include<algorithm> 17 #include<stack> 18 #include<vector> 19 using namespace std; 20 21 const int mx=20005; 22 stack<int>s; 23 vector<int>g[mx]; 24 int dfn[mx],low[mx]; 25 int sccno[mx],vs[mx]; 26 int cut_dfs,cut_scc; 27 int in[mx],out[mx]; 28 29 void Init(int n) 30 { 31 cut_dfs=cut_scc=0; 32 memset(sccno,0,sizeof(sccno)); 33 memset(dfn,0,sizeof(dfn)); 34 memset(low,0,sizeof(low)); 35 memset(vs,0,sizeof(vs)); 36 for (int i=1;i<=n;i++) g[i].clear(); 37 while (!s.empty()) s.pop(); 38 } 39 40 void dfs(int u) 41 { 42 43 s.push(u); 44 low[u]=dfn[u]=++cut_dfs; 45 vs[u]=1; 46 for (int i=0;i<g[u].size();i++) 47 { 48 int v=g[u][i]; 49 if (!vs[v]) 50 { 51 dfs(v); 52 low[u]=min(low[u],low[v]); 53 } 54 else if (!sccno[v]) low[u]=min(low[u],dfn[v]);///一定要加if (!sccno[v]) 55 } 56 57 if (low[u]==dfn[u]) 58 { 59 cut_scc++; 60 while (1) 61 { 62 int v=s.top(); 63 s.pop(); 64 sccno[v]=cut_scc; 65 if (v==u) break; 66 } 67 } 68 } 69 70 int main() 71 { 72 int t,n,m; 73 scanf("%d",&t); 74 while (t--) 75 { 76 scanf("%d%d",&n,&m); 77 Init(n); 78 int a,b; 79 while (m--) 80 { 81 scanf("%d%d",&a,&b); 82 g[a].push_back(b); 83 } 84 for (int i=1;i<=n;i++) 85 { 86 if (!dfn[i]) dfs(i); 87 } 88 89 if (cut_scc==1) 90 { 91 printf("0 "); 92 continue; 93 } 94 for (int i=1;i<=cut_scc;i++) in[i]=out[i]=1; 95 for (int i=1;i<=n;i++) 96 { 97 for (int j=0;j<g[i].size();j++) 98 { 99 int v=g[i][j]; 100 if (sccno[i]!=sccno[v]) out[sccno[i]]=in[sccno[v]]=0; 101 } 102 } 103 a=b=0; 104 for (int i=1;i<=cut_scc;i++) 105 { 106 if (out[i]) a++; 107 if (in[i]) b++; 108 } 109 printf("%d ",max(a,b)); 110 } 111 }