• 图连通性【tarjan点双连通分量、边双联通分量】【无向图】


    根据 李煜东大牛:图连通性若干拓展问题探讨 ppt学习。

    有割点不一定有割边,有割边不一定有割点。

    理解low[u]的定义很重要。

    1.无向图求割点、点双联通分量:

    如果对一条边(x,y),如果low[y]>=dfn[x],表示搜索树中y为根的子树必须要通过x才能到达树的上端,则x必为割点。

    x属于多个点双联通分量,所以出栈的时候保留x(所以栈出到y就好!否则可能会把其他支路的节点一起出栈)。

    附上一个小例子。

    这个打个模板吧。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 using namespace std;
     6 
     7 const int N=1010;
     8 int n,m,al,cnt,num,sl,dfn[N],low[N],vis[N],s[N],first[N],b[N][100];
     9 struct node{int x,y,next;}a[N*2];
    10 
    11 void ins(int x,int y)
    12 {
    13     a[++al].x=x;a[++al].y=y;
    14     a[al].next=first[x];first[x]=al;
    15 }
    16 
    17 int minn(int x,int y){return x<y ? x:y;}
    18 
    19 void tarjan(int x)
    20 {
    21     dfn[x]=low[x]=++num;
    22     s[++sl]=x;
    23     for(int i=first[x];i;i=a[i].next)
    24     {
    25         int y=a[i].y;
    26         if(!dfn[y]) 
    27         {
    28             tarjan(y);
    29             low[x]=minn(low[x],low[y]);
    30             if(low[y]>=dfn[x])//key
    31             {
    32                 cnt++;
    33                 b[cnt][++b[cnt][0]]=x;
    34                 while(1)
    35                 {
    36                     int z=s[sl--];
    37                     b[cnt][++b[cnt][0]]=z;
    38                     if(z==y) break;
    39                 }
    40             }
    41         }
    42         else low[x]=minn(low[x],low[y]);
    43     }
    44 }
    45 
    46 
    47 int main()
    48 {
    49     freopen("a.in","r",stdin);
    50     scanf("%d%d",&n,&m);
    51     al=0;
    52     memset(first,0,sizeof(first));
    53     num=0;cnt=0;sl=0;
    54     memset(dfn,0,sizeof(dfn));
    55     memset(vis,0,sizeof(vis));
    56     memset(b,0,sizeof(b));
    57     for(int i=1;i<=m;i++)
    58     {
    59         int x,y;
    60         scanf("%d%d",&x,&y);
    61         ins(x,y);ins(y,x);
    62     }
    63     for(int i=1;i<=n;i++)
    64         if(!dfn[i]) tarjan(i);
    65     for(int i=1;i<=cnt;i++)
    66     {
    67         for(int j=1;j<=b[i][0];j++)
    68             printf("%d ",b[i][j]);
    69         printf("
    ");
    70     }
    71     return 0;
    72 }

    2.无向图求割边、边双联通分量:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 using namespace std;
     6 
     7 const int N=1010;
     8 int n,m,al,cnt,num,sl,dfn[N],low[N],vis[N],s[N],first[N],b[N][100];
     9 struct node{int x,y,next,tmp;}a[N*2];
    10 
    11 void ins(int x,int y)
    12 {
    13     a[++al].x=x;a[al].y=y;a[al].tmp=0;
    14     a[al].next=first[x];first[x]=al;
    15 }
    16 
    17 int minn(int x,int y){return x<y ? x:y;}
    18 
    19 void tarjan(int x)
    20 {
    21     dfn[x]=low[x]=++num;
    22     s[++sl]=x;
    23     for(int i=first[x];i;i=a[i].next)
    24     {
    25         if(a[i].tmp) continue;
    26         a[i].tmp=1;
    27         a[(i%2)==0 ? i-1:i+1].tmp=1;//key
    28         int y=a[i].y;
    29         if(!dfn[y]) 
    30         {
    31             tarjan(y);
    32             low[x]=minn(low[x],low[y]);
    33             if(low[y]>dfn[x])//key
    34             {
    35                 cnt++;
    36                 while(1)
    37                 {
    38                     int z=s[sl--];
    39                     b[cnt][++b[cnt][0]]=z;
    40                     if(z==y) break;
    41                 }
    42             }
    43         }
    44         else low[x]=minn(low[x],low[y]);//前提:x->y不是搜索树上的边,故前面应该把走过的边的反向边去掉。
    45     }
    46 }
    47 
    48 
    49 int main()
    50 {
    51     //freopen("a.in","r",stdin);
    52     scanf("%d%d",&n,&m);
    53     al=0;
    54     memset(first,0,sizeof(first));
    55     num=0;cnt=0;sl=0;
    56     memset(dfn,0,sizeof(dfn));
    57     memset(vis,0,sizeof(vis));
    58     memset(b,0,sizeof(b));
    59     for(int i=1;i<=m;i++)
    60     {
    61         int x,y;
    62         scanf("%d%d",&x,&y);
    63         ins(x,y);ins(y,x);
    64     }
    65     for(int i=1;i<=n;i++)
    66     {
    67         if(!dfn[i]) 
    68         {
    69             tarjan(i);
    70             if(sl) //key
    71             {
    72                 cnt++;
    73                 b[cnt][0]=sl;
    74                 for(int j=1;j<=sl;j++) b[cnt][j]=s[j];
    75                 sl=0;
    76             }
    77         }
    78     }
    79     for(int i=1;i<=cnt;i++)
    80     {
    81         for(int j=1;j<=b[i][0];j++)
    82             printf("%d ",b[i][j]);
    83         printf("
    ");
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    调试代码的技巧
    关联Lable和输入项
    如何更有效的利用自己的时间
    高效能人士的七个习惯>读书笔记之二
    .NET别名机制简介
    VS2005升SP1错误1718文件FileName被数字签名策略拒绝
    程序物语(三):做人、做事、生活
    程序物语(二):起手式
    SQL Server 2008如何压缩日志(log)文件?
    prototype中文参数乱码解决方案
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/9698812.html
Copyright © 2020-2023  润新知