zoukankan      html  css  js  c++  java
  • wenbao与tarjan

    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
    ", 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
    ", 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
    ", 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
    ", t++);
    49         for(int i = 1; i <= 1000; ++i){
    50             if(b[i]){
    51                 printf("  SPF node %d leaves %d subnets
    ", i, b[i]+1);
    52                 flag = true;
    53             }
    54         }
    55         if(!flag) printf("  No SPF nodes
    ");
    56         printf("
    ");
    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() != '
    '){
    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
    ", sum);
    45     }
    46     return 0;
    47 }

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    只有不断学习才能进步!

  • 相关阅读:
    POJ1811 Prime Test
    HDU3864 D_num
    HDU2138 How many prime numbers
    SPOJ1812 LCS2
    SPOJ1811 LCS
    SPOJ8222 NSUBSTR
    BZOJ4237 稻草人
    洛谷P3601 签到题
    ThreadLocal 线程的私有内存
    netty in action 笔记 二
  • 原文地址:https://www.cnblogs.com/wenbao/p/6774284.html
Copyright © 2011-2022 走看看