Tarjan
求强联通图,割点,桥相关问题
用vis[i]标记i点第几次被访问,low数组标记i点能够到达的最远的祖先,那么当low·[i] == vis[i] 构成联通图。。。low[i] >= vis[i]时为割点(关节点)
1 struct Node{ 2 int from, to, next; 3 }v[maxn]; 4 void add(int from, int to){ 5 v[e].from = from; 6 v[e].to = to; 7 v[e].next = head[from]; 8 head[from] = e++; 9 } 10 int vis[maxn], l[maxn], s[maxn]; 11 void t(int x, int num){ 12 vis[x] = 1; 13 l[x] = num; 14 s[++top] = x; 15 for(int i = head[x]; i != -1; i = v[i].next){ 16 int xx = v[i].to; 17 if(!vis[xx]) t(xx, num+1); 18 if(vis[xx] == 1) l[x] = min(l[xx], l[x]); 19 } 20 if(l[x] == num){ 21 do{ 22 vis[s[top]] = -1; 23 }while(s[top--] != x); 24 } 25 }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=1269
乱入。。。。。。。。。。
这个题并查集什么的随便搞搞就可以了吧,全当练手
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 const int maxn = 1e5+10; 5 int n, m, e, sum; 6 int head[maxn]; 7 bool vis[maxn]; 8 struct Node{ 9 int to, next; 10 }v[maxn]; 11 void add(int from, int to){ 12 v[e].to = to; 13 v[e].next = head[from]; 14 head[from] = e++; 15 } 16 int l[maxn]; 17 void t(int x, int num){ 18 vis[x] = true; 19 l[x] = num; 20 for(int i = head[x]; i != -1; i = v[i].next){ 21 int xx = v[i].to; 22 if(!vis[xx]) t(xx, num+1); 23 l[x] = min(l[xx], l[x]); 24 } 25 if(l[x] == num) sum++; 26 } 27 int main(){ 28 while(~scanf("%d%d", &n, &m) && (n+m)){ 29 memset(head, -1, sizeof(int)*maxn); 30 e = 0, sum = 0; 31 memset(vis, false, sizeof(bool)*maxn); 32 int x, y; 33 for(int i = 0; i < m; ++i){ 34 scanf("%d%d", &x, &y); 35 add(x, y); 36 } 37 for(int i = 1; i <= n; ++i){ 38 if(!vis[i]) t(i, 0); 39 } 40 printf("%s\n", sum == 1 ? "Yes" : "No"); 41 } 42 return 0; 43 }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=1827
中文题
jarjan将强联通图缩为一点
1 #include <iostream> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int maxn = 2e3+10; 6 int n, m, e, top, num2; 7 int a[maxn], b[maxn], head[maxn], d[maxn], f[maxn]; 8 struct Node{ 9 int from, to, next; 10 }v[maxn]; 11 void add(int from, int to){ 12 v[e].from = from; 13 v[e].to = to; 14 v[e].next = head[from]; 15 head[from] = e++; 16 } 17 int vis[maxn], l[maxn], s[maxn]; 18 void t(int x, int num){ 19 vis[x] = 1; 20 l[x] = num; 21 s[++top] = x; 22 for(int i = head[x]; i != -1; i = v[i].next){ 23 int xx = v[i].to; 24 if(!vis[xx]) t(xx, num+1); 25 if(vis[xx] == 1) l[x] = min(l[xx], l[x]); 26 } 27 if(l[x] == num){ 28 int mi = 1e9; 29 do{ 30 d[s[top]] = num2; 31 mi = min(mi, a[s[top]]); 32 vis[s[top]] = -1; 33 }while(s[top--] != x); 34 b[num2++] = mi; 35 } 36 } 37 int main(){ 38 while(~scanf("%d%d", &n, &m)){ 39 for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); 40 memset(head, -1, sizeof(int)*maxn); 41 memset(f, 0, sizeof(int)*maxn); 42 e = 0, top = 0; 43 int x, y, sum = 0, cnt = 0; 44 for(int i = 0; i < m; ++i){ 45 scanf("%d%d", &x, &y); 46 add(x, y); 47 } 48 num2 = 0; 49 memset(vis, 0, sizeof(int)*maxn); 50 for(int i = 1; i <= n; ++i){ 51 if(!vis[i]) t(i, 0); 52 } 53 for(int i = 0; i < e; ++i){ 54 int xx = v[i].from, yy = v[i].to; 55 if(d[xx] != d[yy]) f[d[yy]]++; 56 } 57 for(int i = 0; i < num2; ++i){ 58 if(!f[i]) cnt ++, sum += b[i]; 59 } 60 printf("%d %d\n", cnt, sum); 61 } 62 return 0; 63 }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
http://acm.hdu.edu.cn/showproblem.php?pid=2767
给定有向图,求最少添加多少条边变为强连通图
tarjan缩点,转化为DAG(DAG变为连通图,max(入度为零,出度为零), 注意特殊情况)
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 const int maxn = 50009; 5 struct Node{ 6 int from, to, next; 7 }v[maxn]; 8 int e; 9 int head[maxn], f[maxn], w[maxn]; 10 void add(int from, int to){ 11 v[e].from = from; 12 v[e].to = to; 13 v[e].next = head[from]; 14 head[from] = e++; 15 } 16 int s[maxn], num2, d[maxn], top, l[maxn]; 17 void q(int x, int num){ 18 s[++top] = x; 19 l[x] = num; 20 for(int i = head[x]; i != -1; i = v[i].next){ 21 int xx = v[i].to; 22 if(l[xx] == -1) q(xx, num+1); 23 if(l[xx] >= 0) l[x] = min(l[x], l[xx]); 24 } 25 if(l[x] == num){ 26 do{ 27 l[s[top]] = -2; 28 d[s[top]] = num2; 29 }while(s[top--] != x); 30 num2 ++; 31 } 32 } 33 int main(){ 34 int t, n, m; 35 scanf("%d", &t); 36 while(t--){ 37 scanf("%d%d", &n, &m); 38 memset(head, -1, sizeof(int)*maxn); 39 e = 0, top = 0; 40 int x, y; 41 for(int i = 0; i < m; ++i){ 42 scanf("%d%d", &x, &y); 43 add(x, y); 44 } 45 memset(l, -1, sizeof(int)*maxn); 46 num2 = 0; 47 for(int i = 1; i <= n; ++i){ 48 if(l[i] == -1) q(i, 0); 49 } 50 memset(f, 0, sizeof(int)*maxn); 51 memset(w, 0, sizeof(int)*maxn); 52 for(int i = 0; i < e; ++i){ 53 int xx = v[i].from, yy = v[i].to; 54 if(d[xx] != d[yy]){ 55 f[d[xx]] ++, w[d[yy]] ++; 56 } 57 } 58 int sum1 = 0, sum2 = 0; 59 for(int i = 0; i < num2; ++i){ 60 if(!f[i]) sum1 ++; 61 if(!w[i]) sum2 ++; 62 } 63 sum1 = max(sum1, sum2); 64 printf("%d\n", sum1 == 1 ? 0 : sum1); 65 } 66 return 0; 67 }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
http://poj.org/problem?id=1523
求无向图的割点,,
一样的套路
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 const int maxn = 2e3+10; 5 struct Node{ 6 int from, to, next; 7 }v[maxn]; 8 int e, head[maxn]; 9 void add(int from, int to){ 10 v[e].from = from; 11 v[e].to = to; 12 v[e].next = head[from]; 13 head[from] = e ++; 14 } 15 int l[maxn], b[maxn]; 16 void d(int x, int num){ 17 l[x] = num; 18 int mi = 1e9; 19 for(int i = head[x]; i != -1; i = v[i].next){ 20 int xx = v[i].to; 21 if(l[xx] == -1){ 22 d(xx, num+1); 23 if(l[xx] >= num){ 24 //cout<<xx<<" "<<x<<" "<<l[xx]<<endl; 25 b[x] ++; 26 } 27 } 28 mi = min(mi, l[xx]); 29 } 30 l[x] = mi; 31 if(num == 0) b[x] --; 32 } 33 int main(){ 34 int x, y, t = 1, ma; 35 while(~scanf("%d", &x) && x){ 36 memset(head, -1, sizeof(int)*maxn); 37 e = 0; 38 scanf("%d", &y); 39 add(x, y), add(y, x); 40 while(~scanf("%d", &x) && x){ 41 scanf("%d", &y); 42 add(x, y), add(y, x); 43 } 44 memset(l, -1, sizeof(int)*maxn); 45 memset(b, 0, sizeof(int)*maxn); 46 d(y, 0); 47 bool flag = false; 48 printf("Network #%d\n", t++); 49 for(int i = 1; i <= 1000; ++i){ 50 if(b[i]){ 51 printf(" SPF node %d leaves %d subnets\n", i, b[i]+1); 52 flag = true; 53 } 54 } 55 if(!flag) printf(" No SPF nodes\n"); 56 printf("\n"); 57 } 58 return 0; 59 }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
http://poj.org/problem?id=1144
求割点
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 const int maxn = 2e4+10; 5 struct Node{ 6 int from, to, next; 7 }v[maxn]; 8 int head[maxn], e; 9 void add(int from, int to){ 10 v[e].from = from; 11 v[e].to = to; 12 v[e].next = head[from]; 13 head[from] = e++; 14 } 15 int l[maxn], sum; 16 void d(int x, int num){ 17 l[x] = num; 18 int mi = 1e9, num2 = 0; 19 for(int i = head[x]; i != -1; i = v[i].next){ 20 int xx = v[i].to; 21 if(l[xx] == -1){ 22 d(xx, num+1); 23 if(l[xx] >= num) num2 ++; 24 } 25 mi = min(mi, l[xx]); 26 } 27 l[x] = mi; 28 if(num == 0) num2 --; 29 if(num2) sum ++; 30 } 31 int main(){ 32 int n, x, y; 33 while(~scanf("%d", &n) && n){ 34 memset(head, -1, sizeof(int)*maxn); 35 e = 0, sum = 0; 36 while(~scanf("%d", &x) && x){ 37 while(getchar() != ‘\n‘){ 38 scanf("%d", &y); 39 add(x, y), add(y, x); 40 } 41 } 42 memset(l, -1, sizeof(int)*maxn); 43 d(1, 0); 44 printf("%d\n", sum); 45 } 46 return 0; 47 }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
只有不断学习才能进步!
原文:https://www.cnblogs.com/wenbao/p/6774284.html