zoukankan      html  css  js  c++  java
  • hiho图的联通性(自留)

    无向图割边割点算法

    而当(u,v)为树边且low[v]>dfn[u]时,表示v节点只能通过该边(u,v)与u连通,那么(u,v)即为割边。

     1 void dfs(int u) {
     2     //记录dfs遍历次序
     3     static int counter = 0;    
     4     
     5     //记录节点u的子树数
     6     int children = 0;
     7     
     8     ArcNode *p = graph[u].firstArc;
     9     visit[u] = 1;
    10 
    11     //初始化dfn与low
    12     dfn[u] = low[u] = ++counter;
    13 
    14     for(; p != NULL; p = p->next) {
    15         int v = p->adjvex;
    16         
    17         //节点v未被访问,则(u,v)为树边
    18         if(!visit[v]) {
    19             children++;
    20             parent[v] = u;
    21             dfs(v);
    22 
    23             low[u] = min(low[u], low[v]);
    24 
    25             //case (1)
    26             if(parent[u] == NIL && children > 1) {
    27                 printf("articulation point: %d
    ", u);
    28             }
    29 
    30             //case (2)
    31             if(parent[u] != NIL && low[v] >= dfn[u]) {
    32                 printf("articulation point: %d
    ", u);
    33             }
    34             
    35             //bridge
    36             if(low[v] > dfn[u]) {
    37                 printf("bridge: %d %d
    ", u, v);
    38             }
    39         }
    40 
    41         //节点v已访问,则(u,v)为回边
    42         else if(v != parent[u]) {
    43             low[u] = min(low[u], dfn[v]);
    44         }
    45     }
    46 }
    View Code

    边双联通分量算法

    对于一个无向图的子图,当删除其中任意一个点后,不改变图内点的连通性,这样的子图叫做点的双连通子图。而当子图的边数达到最大时,叫做点的双连通分量。

    直观的做法自然先用上周的算法求出所有桥,去掉所有桥之后再做DFS求出每一个连通子图。我们这周要介绍一种更"抽象"的算法,通过在Tarjan算法当中巧妙地用一个栈来统计出每一个组内的节点,其代码如下:

     1 void dfs(int u) {
     2     //记录dfs遍历次序
     3     static int counter = 0;    
     4     
     5     //记录节点u的子树数
     6     int children = 0;
     7     
     8     ArcNode *p = graph[u].firstArc;
     9     visit[u] = 1;
    10 
    11     //初始化dfn与low
    12     dfn[u] = low[u] = ++counter;
    13     
    14     //将u加入栈
    15     stack[++top] = u;
    16 
    17     for(; p != NULL; p = p->next) {
    18         int v = p->adjvex;
    19         
    20         //节点v未被访问,则(u,v)为树边
    21         if(!visit[v]) {
    22             children++;
    23             parent[v] = u;
    24             dfs(v);
    25 
    26             low[u] = min(low[u], low[v]);
    27             if (low[v] > dfn[u]) {
    28                 printf("bridge: %d %d
    ", u, v);    // 该边是桥
    29                 bridgeCnt++;  
    30             }
    31         }
    32 
    33         //节点v已访问,则(u,v)为回边
    34         else if(v != parent[u]) {
    35             low[u] = min(low[u], dfn[v]);
    36         }
    37     }
    38     
    39     if (low[u] == dfn[u])
    40     {
    41         // 因为low[u] == dfn[u],对(parent[u],u)来说有dfn[u] > dfn[ parent[u] ],因此low[u] > dfn[ parent[u] ]
    42         // 所以(parent[u],u)一定是一个桥,那么此时栈内在u之前入栈的点和u被该桥分割开
    43         // 则u和之后入栈的节点属于同一个组
    44         将从u到栈顶所有的元素标记为一个组,并弹出这些元素。
    45     }
    46 }
    View Code

    强连通分量

    对于有向图上的2个点a,b,若存在一条从a到b的路径,也存在一条从b到a的路径,那么称a,b是强连通的。
    对于有向图上的一个子图,若子图内任意点对(a,b)都满足强连通,则称该子图为强连通子图。
    非强连通图有向图的极大强连通子图,称为强连通分量。
    特别地,和任何一个点都不强连通的单个点也是一个强连通分量。

     1 tarjan(u)
     2 {
     3     Dfn[u]=Low[u]=++Index                      // 为节点u设定次序编号和Low初值
     4     Stack.push(u)                              // 将节点u压入栈中
     5     for each (u, v) in E                       // 枚举每一条边
     6         if (v is not visted)                   // 如果节点v未被访问过
     7             tarjan(v)                          // 继续向下找
     8             Low[u] = min(Low[u], Low[v])
     9         else if (v in Stack)                   // 如果节点v还在栈内(很重要,无向图没有这一步)
    10             Low[u] = min(Low[u], Dfn[v])
    11     if (Dfn[u] == Low[u])                      // 如果节点u是强连通分量的根
    12         repeat
    13             v = Stack.pop                      // 将v退栈,为该强连通分量中一个顶点
    14             mark v                             // 标记v,同样通过栈来找连通分量
    15         until (u == v)
    16 }
    View Code


    scc + 缩点 + topo

    对于一个无向图的子图,当删除其中任意一个点后,不改变图内点的连通性,这样的子图叫做点的双连通子图。而当子图的边数达到最大时,叫做点的双连通分量。

                                           

    对于桥的两种情况,它分割个区域数刚好就等于割点数+1;而连通分量内的割点同样也是,每存在一个割点,点的双连通分量就增加一个。

    点的双连通分量就等于割点数量加1。

    每存在一个割点,就把一个区域一分为二,所以最后的结果也就是统计割点的数量就可以了。而对于分组具体情况,我们仍然采用栈来辅助我们记录

     1 void dfs(int u) {
     2     //记录dfs遍历次序
     3     static int counter = 0;    
     4     
     5     //记录节点u的子树数
     6     int children = 0;
     7     
     8     ArcNode *p = graph[u].firstArc;
     9     visit[u] = 1;
    10 
    11     //初始化dfn与low
    12     dfn[u] = low[u] = ++counter;
    13 
    14     for(; p != NULL; p = p->next) {
    15         int v = p->adjvex;
    16         if(edge(u,v)已经被标记) continue; 
    17 
    18         //节点v未被访问,则(u,v)为树边
    19         if(!visit[v]) {
    20             children++;
    21             parent[v] = u;
    22             edgeStack[top++] = edge(u,v); // 将边入栈
    23             dfs(v);
    24             
    25             low[u] = min(low[u], low[v]);
    26 
    27             //case (1)
    28             if(parent[u] == NIL && children > 1) {
    29                 printf("articulation point: %d
    ", u);
    30                 // mark edge
    31                 // 将边出栈,直到当前边出栈为止,这些边标记为同一个组
    32                 do {
    33                     nowEdge = edgeStack[top];
    34                     top--;
    35                     // 标记nowEdge
    36                 }    while (nowEdge != edge(u,v))
    37             }
    38 
    39             //case (2)
    40             if(parent[u] != NIL && low[v] >= dfn[u]) {
    41                 printf("articulation point: %d
    ", u);
    42                 // mark edge
    43                 // 将边出栈,直到当前边出栈为止,这些边标记为同一个组
    44                 do {
    45                     nowEdge = edgeStack[top];
    46                     top--;
    47                     // 标记nowEdge
    48                 }    while (nowEdge != edge(u,v))
    49             }
    50             
    51         }
    52 
    53         //节点v已访问,则(u,v)为回边
    54         else if(v != parent[u]) {
    55             edgeStack[top++] = edge(u,v);
    56             low[u] = min(low[u], dfn[v]);
    57         }
    58     }
    59 }
    View Code
  • 相关阅读:
    Python3+Selenium3自动化测试-(四)
    Python3+Selenium3自动化测试-(三)
    Python3+Selenium3自动化测试-(二)
    Python3+Selenium3自动化测试-(一)
    Python3+Selenium3自动化测试-(准备)
    mysql报错MySQLSyntaxErrorException: Specified key was too long; max key length is 767 byte
    C# 基础Array
    c# 基础之方法
    c#之初识结构(Struct)
    c# 之Enum--枚举
  • 原文地址:https://www.cnblogs.com/usedrosee/p/4693121.html
Copyright © 2011-2022 走看看