题目大意
一个有向图 n(1<=n<=20000) 个点 m(0<=m<=50000) 条边
问至少添加几条边,使得整个图是一个强连通图
做法分析
先缩点,然后找出 DAG 中入度为 0 的点的个数和出度为 0 的点的个数,输出较大者(PS:这是一个结论)
参考代码

1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <stack> 5 6 using namespace std; 7 8 struct Edge 9 { 10 int en, next; 11 Edge() {} 12 Edge(int a, int b) 13 { 14 en=a, next=b; 15 } 16 } edge[50006]; 17 int head[20006], tot; 18 int dfn[20006], low[20006], T, in[20006]; 19 int id[20006], ind; 20 stack<int> S; 21 int t, n, m; 22 23 void add_edge(int st, int en) 24 { 25 edge[tot]=Edge(en, head[st]); 26 head[st]=tot++; 27 } 28 29 void tarjan(int u) 30 { 31 dfn[u]=low[u]=T++; 32 S.push(u), in[u]=1; 33 for(int e=head[u]; e!=-1; e=edge[e].next) 34 { 35 int v=edge[e].en; 36 if(dfn[v]==-1) 37 { 38 tarjan(v); 39 low[u]=min(low[u], low[v]); 40 } 41 else if(in[v] && dfn[v]<low[u]) low[u]=dfn[v]; 42 } 43 if(dfn[u]==low[u]) 44 { 45 ind++; 46 for(int v; v=S.top(); ) 47 { 48 id[v]=ind; 49 in[v]=0, S.pop(); 50 if(v==u) break; 51 } 52 } 53 } 54 55 int main() 56 { 57 scanf("%d", &t); 58 for(int ca=1; ca<=t; ca++) 59 { 60 scanf("%d%d", &n, &m); 61 memset(head, -1, sizeof head); 62 tot=0; 63 for(int i=0, st, en; i<m; i++) 64 { 65 scanf("%d%d", &st, &en); 66 add_edge(st, en); 67 } 68 memset(in, 0, sizeof in); 69 memset(dfn, -1, sizeof dfn); 70 ind=-1; 71 while(!S.empty()) S.pop(); 72 for(int i=1; i<=n; i++) 73 if(dfn[i]==-1) tarjan(i); 74 if(ind==0) 75 { 76 printf("0\n"); 77 continue; 78 } 79 memset(dfn, 0, sizeof dfn); 80 memset(low, 0, sizeof low); 81 for(int i=1; i<=n; i++) 82 { 83 for(int e=head[i]; e!=-1; e=edge[e].next) 84 { 85 if(id[i]!=id[edge[e].en]) dfn[id[i]]++, low[id[edge[e].en]]++; 86 } 87 } 88 int ans1=0, ans2=0; 89 for(int i=0; i<=ind; i++) 90 { 91 if(dfn[i]==0) ans1++; 92 if(low[i]==0) ans2++; 93 } 94 printf("%d\n", max(ans1, ans2)); 95 } 96 return 0; 97 }