• 割点和桥---Tarjan算法


    使用Tarjan算法求解图的割点和桥。

    1、割点

         主要的算法结构就是DFS,一个点是割点,当且仅当以下两种情况:
            (1)该节点是根节点,且有两棵以上的子树;
            (2)该节点的任一子节点,没有到该节点祖先的反向边(就是说如果没有这个割点,那么这个子节点和那个祖先之间不连通);

     1 void cutpoint_Tarjan(int u,int parent)
     2 {
     3     int son;  //节点m的儿子节点
     4     ENode *ptr=(ENode *)malloc(sizeof(ENode));
     5 
     6     dfn[u]=low[u]=depth++;  //访问+标记+遍历
     7     vis[u]=1;
     8     ptr=ALG->vlist[u].firstedge;
     9     while(ptr!=NULL)
    10     {
    11         son=ptr->key;
    12         if(!vis[son])
    13         {
    14             DFS(son,u);
    15             low[u]=MIN(low[u],low[son]);
    16 
    17             if(u==root)    //不同之处//根节点[要定义初始访问节点,因为要考虑割点的2个判断条件]
    18                 cut[u]++;
    19             else if(u!=root && dfn[u] <= low[son])
    20                 cut[u]++;  //m是割点 
    21         }
    22         else if(son != parent)  //有后向边
    23         {
    24             low[u]=MIN(low[u],dfn[son]);
    25         }
    26         ptr=ptr->next;
    27     }
    28 }

    2、桥

    Tarjan算法求割边(桥):
    【1】使用(son!=parent && dfn[son]<dfn[u]);

     1 void init_Tarjan(void)
     2 {
     3     depth=0;
     4     for(int i=0;i<ALG->n;i++)
     5     {
     6         dfn[i]=low[i]=-1;
     7         vis[i]=0;
     8     }
     9 
    10     num_bridge=0;
    11     for(int j=0;j<ALG->e;j++)
    12     {
    13         bridge_Node[j].front=0;
    14         bridge_Node[j].rear =0;
    15     }
    16 }
    17 
    18 void Add_to_BNode(int front,int rear)  //从坐标1开始存储
    19 {
    20     bridge_Node[num_bridge].front=front;
    21     bridge_Node[num_bridge].rear =rear;
    22 }
    23 
    24 void bridgenode_Tarjan(int u,int parent)
    25 {
    26     int son;
    27     ENode *ptr=(ENode*)malloc(sizeof(ENode));
    28 
    29     dfn[u]=low[u]=depth++;  //访问+标记+遍历
    30     vis[u]=1;
    31     ptr=ALG->vlist[u].firstedge;
    32     while(ptr!=NULL)
    33     {
    34         son=ptr->key;
    35         if(son!=parent && dfn[son]<dfn[u])  //避免走重边,效果和id一样
    36         {
    37             if(!vis[son])
    38             {
    39                 bridge_node_Tarjan(son,u);
    40                 low[u]=MIN(low[u],low[son]);
    41                 if(low[son] > dfn[u])  //(u,son)是桥
    42                 {
    43                     num_bridge++;
    44                     Add_to_BNode(u,son);  //存储桥            
    45                 }
    46             }
    47             else if(son != parent)
    48             {
    49                 low[u]=MIN(low[u],dfn[son]);
    50             }
    51         }
    52         ptr=ptr->next;
    53     }
    54 }

    【2】为每一条边标号 id记录每条边(一条无向边拆成的两条有向边id相同),每个点的父亲到它的边的标号;

     1 //结点定义  /*****注意边表节点定义有所变化****/
     2 typedef struct edge_node{
     3     int key;   //儿子节点[边的终点]
     4     int id;    //边的编号
     5     struct edge_node *next;
     6 }ENode;
     7 void init_Tarjan(void)  //Tarjan算法初始化
     8 {
     9     depth=0;
    10     for(int i=0;i<ALG->n;i++)
    11     {
    12         vis[i]=0;
    13         dfn[i]=low[i]=-1;
    14     }
    15     count_bridge=0;
    16     for(int j=1;j<=ALG->e;j++)  //取值于1-e
    17         bridge[j]=0;
    18 }
    19 void bridge_Tarjan(int u,int id)  //id是u的父亲边的编号
    20 {    
    21     int son;  //u的儿子节点
    22     ENode *ptr=(ENode *)malloc(sizeof(ENode));
    23 
    24     dfn[u]=low[u]=depth++;  //访问+标记+遍历
    25     vis[u]=1;
    26     ptr=ALG->vlist[u].firstedge;
    27     while(ptr!=NULL)
    28     {
    29         if(ptr->id != id)  //避免走重边,相当于cutpoint_Tarjan中的(son != parent)
    30         {
    31             son=ptr->key;
    32             if(!vis[son])
    33             {
    34                 bridge_Tarjan(son,ptr->id);
    35                 low[u]=MIN(low[u],low[son]);
    36                 if(dfn[u] < low[son])   //注意不取等号,当DFN[u]==LOW[v]时,当u->v dfs递归,存在一条v->u的回边,使得LOW[v]=DFN[u];故不为桥
    37                 {
    38                     bridge[ptr->id]=1;  //第id边是桥
    39                     printf("(%c,%c) ",ALG->vlist[u].vertex,ALG->vlist[son].vertex);  //用于输出割边
    40                 }
    41             }
    42             else
    43             {
    44                 low[u]=MIN(low[u],dfn[son]);
    45             }
    46         }
    47         ptr=ptr->next;
    48     }
    49 }
    ---  纵使山重水复,亦会柳暗花明   sunqh1991@163.com   欢迎关注,互相交流
  • 相关阅读:
    Delphi 获取时间的年月日
    Tlist删除技巧
    SQL Server 2008 允许远程连接的配置
    initialization & finalization
    display属性(元素转换)
    float 浮动
    盒模型
    行内元素和块级元素水平及垂直居中
    html常用的几个标签
    html基础
  • 原文地址:https://www.cnblogs.com/wjcx-sqh/p/5929926.html
Copyright © 2020-2023  润新知