hDU2767Equivalences【强连通缩点+添加多少条边可以使有向图强连通】
大意:
告诉你有n个点 m条单向边 问最少添加多少条边能将该图变成强连通
分析:
先用强连通进行缩点 缩成一个有向无环图
然后我们考虑如何才能使 这个有向无环图变成一个强连通
我的第一反应是求最小路径覆盖 然后再首尾相连 结果时间复杂度承受不住
其实想到这里可以大胆猜想一下了
刚刚提到了 首尾连接这个思想
我们只要统计有多少个头多少个尾 然后用尾去连接头就好了 答案就是首尾最大值
统计首尾也就是统计入度出度为0的点的个数
需要注意的是 若强连通缩点之后点缩成了一个 那么这个点本身就是一个强连通
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <map> 5 #define clr(x) memset(x, 0, sizeof(x)) 6 using namespace std; 7 int min(int a, int b) { 8 return a > b ? b : a; 9 } 10 11 const int maxn = 500005; 12 const int maxm = 500005; 13 14 struct Edge { 15 int to, next; 16 }e[maxm]; 17 int tot; 18 int head[maxn]; 19 int id[maxn]; 20 21 void add(int u, int v) { 22 e[tot].to = v; 23 e[tot].next = head[u]; 24 head[u] = tot++; 25 } 26 int n, m; 27 28 int s[maxn]; 29 int ins[maxn]; 30 int s_cnt; 31 int id_cnt; 32 int cnt; 33 int dfn[maxn], low[maxn]; 34 void dfs(int u) { 35 s[s_cnt++] = u; 36 ins[u] = 1; 37 dfn[u] = low[u] = cnt++; 38 for(int i = head[u]; i; i = e[i].next) { 39 int v = e[i].to; 40 if(!dfn[v]) { 41 dfs(v); 42 low[u] = min(low[u], low[v]); 43 } else if(ins[v]) { 44 low[u] = min(low[u], dfn[v]); 45 } 46 } 47 if(dfn[u] == low[u]) { 48 int x; 49 id_cnt++; 50 do { 51 x = s[--s_cnt]; 52 ins[x] = 0; 53 id[x] = id_cnt; 54 } while(x != u); 55 } 56 } 57 58 void init() { 59 clr(head); 60 clr(dfn); 61 clr(low); 62 clr(id); 63 clr(ins); 64 cnt = 1; 65 s_cnt = 1; 66 id_cnt = 0; 67 tot = 1; 68 } 69 int ind[maxn], outd[maxn]; 70 71 int main() { 72 int t; 73 scanf("%d",&t); 74 int u, v; 75 while(t--) { 76 scanf("%d %d",&n, &m); 77 init(); 78 for(int i = 1; i <= m; i++) { 79 scanf("%d %d",&u, &v); 80 add(u, v); 81 } 82 for(int i = 1; i <= n; i++) { 83 if(!dfn[i]) { 84 dfs(i); 85 } 86 } 87 if(id_cnt == 1) { 88 printf("%d\n", 0); 89 continue; 90 } 91 int ans1 = 0; int ans2 = 0; 92 clr(ind); clr(outd); 93 for(int i = 1; i <= n; i++) { 94 for(int j = head[i]; j; j = e[j].next) { 95 int x = e[j].to; 96 if(id[i] != id[x]) { 97 ind[id[x]]++; 98 outd[id[i]]++; 99 } 100 } 101 } 102 for(int i = 1; i <= id_cnt; i++) { 103 if(ind[i] == 0) ans1++; 104 if(outd[i] == 0) ans2++; 105 } 106 if(ans1 < ans2) ans1 = ans2; 107 printf("%d\n", ans1); 108 } 109 return 0; 110 } 111 112