精华内容
下载资源
问答
  • 图的关节点

    2013-04-09 22:00:29
    直接实现无向图的关节点求解问题,找出所有关节点
  • 计算图的关节点

    2019-10-02 20:26:36
    图的关节点:  如果删去某个节点及依附在该节点上的边后,该图被分割为两个或两个以上的连通图,则该节点为关节点。 计算关节点的关键思路:  在该图的深度优先生成树上,如果某个节点的孩子节点(不一定是...

    图的关节点:

      如果删去某个节点及依附在该节点上的边后,该图被分割为两个或两个以上的连通图,则该节点为关节点。

    计算关节点的关键思路:

      在该图的深度优先生成树上,如果某个节点的孩子节点(不一定是二叉树,孩子节点可能大于2)的子树中,所有孩子节点的子树中都有回边能回到该节点的祖先上,则该节点不是关键节点,因为即使删除了该节点,该节点的祖先或它的孩子都能通过回边将彼此连结起来。与之对应,如果该节点的孩子节点中,但凡有一个孩子节点的子树中没有回边,则该节点一定为关键节点,因为即使其他的孩子节点都有回边,但删除该节点后,这个没有回边的孩子节点还是与被删节点的祖先间分割开了。

    一点不是问题的问题:

      对于当前节点v,在不考虑v是整个树的根节点的情况下,v只有在它的某一个子树w中,w及w的子节点里不存在到v的父母或祖先节点的回边的情况下,v才是关键节点(只有在v的所有的孩子节点的子树上都有回边才不算关键点,P177中,G5的B只有在C上才有回边,因此B仍然为关键节点)。

      现在对low(v):

    Low(v)在visited[v],low[w],visited[k]中找最小值,w为v的孩子节点,k为与v有回边的父母或祖先节点。

    首先看vistited[v],对visited[v]来说,它是v的被访问顺序,由于访问时使用的前序遍历,因此越靠近叶子节点的节点visited值越大。

    再看low[w],low[w]是用于统计v的孩子节点的回边的情况的,现在加入v没有回边回到它的祖先的回边,但如果它的子节点w有或w的子节点里有,则等价于v也有了这个回边,因为v可以通过w来访问到v的祖先。

      对于visited[k],这个用于统计v到祖先的回边。

    Low(v)的过程,实际上就是比较visited[v],low[w],visited[k]的大小,如果low[w]最小,说明v的子节点w的子树中有回边到v的祖先,如果visited[k]最小,说明v有到v的祖先的回边。

    计算得到的low(v),是用于判断v的父亲节点是否为关键节点的,因为low(v)是v所能到达的最浅的节点,它要么是它被访问的顺序(visited[v]),要么是通过子树回边到达的最浅节点(low(w)),要么是通过自己的回边到达的最浅节点(visited[k])。

    对一个节点,当它的孩子节点的最浅节点小于它的被访问顺序,也就是low[w]<visited[v]时,说明v的孩子节点中有回边绕过了v到达了v的祖先。如果v的所有孩子节点都有这样的回边,则删除v后祖先节点一样能通过回边访问到v的孩子,而不影响连通性。

    而如果只要有一个孩子节点使low[w]>=visited[v],也就是代表该孩子节点无法绕过v,则v就是关键节点,因为祖先节点无法绕过v访问这个孩子。

    转载于:https://www.cnblogs.com/lxy-xf/p/11283811.html

    展开全文
  • 关于图的关节点算法

    2012-02-22 12:31:22
    图的关节点算法是搜索的重要应用之一
  • 连通图的关节点算法

    2019-09-08 11:10:23
    //---连通图的关节点寻找算法---// //连通图的深度优先生成树中关节点特性: //1.若生成树的根有两棵或两棵以上的子树,则此根顶点必为关节点,因为图中不存在联结不同子树中顶点的边; //2.若生成树中某个非叶子...
    //---连通图的关节点寻找算法---//
    //连通图的深度优先生成树中关节点特性:
    //1.若生成树的根有两棵或两棵以上的子树,则此根顶点必为关节点,因为图中不存在联结不同子树中顶点的边;
    //2.若生成树中某个非叶子顶点,其某棵子树的结点均没有指向该结点的祖先的回边,则该结点必为关节点。
    #include <stdio.h>
    #include <stdlib.h>
    #include "AdjacencyList.h"
    
    typedef enum {FALSE,TRUE}Boolean;
    int count;                          //计数已访问的点的数量,用于判断根结点是否为关节点
    int DFN[MAX_VERTEX_NUM];        //深度优先搜索树中点i访问的顺序
    int LOW[MAX_VERTEX_NUM];            //深度优先搜索树中点i所能回溯到的最浅层的点(如不能回溯,则为自己)
    
    void FindArticul(ALGraph G);        //寻找关节点算法
    void DFSArticul(ALGraph G,int v);   //从v点开始深度优先遍历寻找关节点
    
    int main()
    {
        ALGraph *G;
        G=(ALGraph *)malloc(sizeof(ALGraph));
    
        CreateGraph(G);
        int i,j;
        printf("图结构(邻接表表示):\n");
        for(i=0;i<G->vexnum;i++)
        {
            ArcNode *p;
            p=(ArcNode *)malloc(sizeof(ArcNode));
            p=G->vertices[i].firstarc;
            printf("%c ",G->vertices[i].data);
            while(p)
            {
                VertexType t;
                int k;
                k=p->adjvex;
                t=G->vertices[k].data;
                printf("%c ",t);
    
                p=p->nextarc;
            }
            printf("\n");
        }
        FindArticul(*G);
        return 0;
    }
    void FindArticul(ALGraph G)
    {
        count=1;
        DFN[0]=1;          //设定邻接表上0号顶点为生成树的根
    
        int i,v;
        for(i=1;i<G.vexnum;i++)
            DFN[i]=0;      //其余顶点初始化为未访问
    
        ArcNode *p;
        p=(ArcNode *)malloc(sizeof(ArcNode));
        p=G.vertices[0].firstarc;
        v=p->adjvex;        //第一个顶点的第一个邻接点
    
        printf("关节点:");
        DFSArticul(G,v);    //从第一个邻接点v点开始深度优先查找关节点
    
        if(count<G.vexnum)  //即从第一个顶点的第一个邻接点出发进行深度遍历后,尚有点未被遍历到,则以顶点为根的搜索树有除第一个邻接点遍历形成的搜索子树外,还有其他搜索子树
        {
            printf("%c ",G.vertices[0].data);
            while(p->nextarc)
            {
                p=p->nextarc;
                v=p->adjvex;
                if(DFN[v]==0)   //第一个顶点的其他邻接点如果未被访问,则再从其开始进行深度优先遍历
                    DFSArticul(G,v);
            }
        }
    }
    //---从v点开始进行深度优先遍历---//
    void DFSArticul(ALGraph G,int v)
    {
        int min,w;
        DFN[v]=min=++count;   //表示结点v被访问的顺序,即count
        Boolean Articul;
        Articul=FALSE;
    
        ArcNode *p;
        p=(ArcNode *)malloc(sizeof(ArcNode));
        //for循环为继续深度优先遍历结点的邻接点
        for(p=G.vertices[v].firstarc;p;p=p->nextarc)
        {
            w=p->adjvex;        //v的邻接点w
            if(DFN[w]==0)
            {
                DFSArticul(G,w);    //如果未被访问,则再从它开始深度优先遍历
                if(LOW[w]<min)
                    min=LOW[w];
    
                if(LOW[w]>=DFN[v])
                    Articul=TRUE;   //如果存在子结点的LOW值不小于本结点的访问顺序值,则本结点为关节点
            }
            else if(DFN[w]<min)   //如果v的邻接点w已被访问,则意味着有往上的回边
                min=DFN[w];
        }
        //for循环结束即为完成邻接点的深度优先遍历,回溯到本结点
        if(Articul)
            printf("%c ",G.vertices[v].data);
        LOW[v]=min;     //LOW[v]设定为子树(邻接点)中的最小值
    }
    
    展开全文
  • 数据结构复习–求图的关节点(Tarjan算法) 文章目录重连通图的关节点(割点)深度优先生成树与回边Visited数组与Low数组Low数组求法 重连通图的关节点(割点) 关节点 若连通图中某个顶点和其相关联的边被删去后,...

    数据结构复习–求图的关节点(Tarjan算法)

    重连通图的关节点(割点)

    关节点

    若连通图中某个顶点和其相关联的边被删去后,该连通图被分割成两个或两个以上的联通分量,则称此节点为关节点(割点)。

    重(双)连通图

    没有关节点的连通图称为双连通图。
    即从一个双连通图中删去任何一个顶点及其想关联的边,它仍为一个连通图。

    深度优先生成树与回边

    从图中任意顶点开始,执行深度优先搜索并在顶点被访问时给它们编号。
    而对于图中实际存在而深度优先生成树中不存在的边,称为回边(v,w)或背向边(v,w)。
    如下例,虚线部分表示回边。

    在这里插入图片描述
    在这里插入图片描述

    Visited数组与Low数组

    visited数组

    第一次对图执行深度优先搜索时,依次访问节点,同时按访问顺序对节点编号。对于每一个节点v,我们称其先序序号为visited[v]。

    low数组

    然后对深度优先搜索树上的每一个节点v,计算编号最低的顶点,称之为low[v]。
    其意义为(个人理解):通过该点,经过零条或多条边及最多一条回边,可以到达的顶点的编号的最小值。例如上图中的C点,其先序编号为3,但可首先通过一条边达到D点,并通过D的回边到达A,所以其low数组编号,及可到达的最低节点编号为1。

    上图中顶点的数字标注为visited[v]/low[v]。

    Low数组求法

    在这里插入图片描述

    解释:对于任意一个顶点V,其low数组值为自身先序编号(visited[v]),其所有孩子节点的low值的最小值,与其通过回边相连的祖先节点K的先序编号(visited[k])这三者中的最小值。

    关节点的判定

    1.若生成树中根节点顶点V,其子树个数大于1,则该节点一定为关节点(易理解)。
    2.对于非根节点v,它是割点当且仅当它有某个儿子w,使得Low[w]>=Visited[v]。注:该条件在根处总是满足,所以需要进行特别判断。
    上例中顶点C与D为关节点。

    Low[w]>=Visited[v]的理解:

    Low[w]>=Visited[v]含义为,v有某个孩子w,其可到达的节点的最低先序编号大于等于其父亲的先序编号。即w一定不可能到达比v先序编号低的节点(深度优先搜索中比v先访问的节点),则删除节点v后,w一定不能与v之前的节点相连,则该图不为连通图。

    Tarjan算法

    Tarjan算法为求关节点的常用算法,其时间复杂度为O(V+E)。

    void FindArticul(ALGraph G){
     //连通图G以邻接表作存储结构,查找并输出G上全部关节点。全局量count对访问计数。
     count = 1; visited[0] = 1;   //设定邻接表上0号顶点为生成树的根 
     for( i=1; i<G.vexnum; ++i)   //其余顶点清零,尚未访问。 
     visited[i]=0;
     p=G.vertices[0].firstarc;   //p为0号顶点指向的第一条依附于它的弧。 
     v=p->adjvex;                //v为该弧所指向的顶点的位置。(即树的根结点) 
     
     DFSArticul(G,v);             //从第v顶点出发深度优先查找关节点 
     if(count<G.vexnum)           //生成树的根至少有两颗子树 
     {
      printf(0,G.vertices[0].data);   //根是关节点,输出 
      while(p->nextarc)         //指向下一条弧 
      {
       p=p->nextarc;
       v=p->adjvex;         
       if(visited[v]==0)
       DFSArticul(g,v);
       } 
     }
    }
    
    void DFSArticul(ALGraph G,int v0){   //在深度遍历,标记visited[v]的同时检查关节点 
     //从第v0个顶点出发深度优先遍历图G,查找并输出G上全部关节点。全局count对访问计数。 
     visited[v0]=min=++count;
     for(p=G.vertices[0].firstarc;p;p=p->nextarc){    //对v0的每个邻接顶点检查 
      w=p->adjvex;           //w为v0邻接顶点
      if(visited[w]==0)      //w未曾访问,是v0的孩子; 注:结点v的low与其孩子有关,所以一定先递归求出节点的所有子树的low值。 
      {
       DFSArticul(G,w);    //返回前求得low[w];
       if(low[w]<min)  min=low[w];
       if(low[w]>=visited[v0])
       printf(v0,G.vertices[v0].data);    //输出关节点;         
       } 
      else if(visited[w]<min)     //不是孩子节点,则为v0节点的祖先(回边) 
      min=visited[w];
     }
     low[v0]=min;
    }
    

    注意点:

    1.搜索树的根节点需要特判
    2.对于每个顶点V,其low一定要在其所有孩子的low值已知的情况下才能决定,所以在算法中要先递归调用求出所有子树的low值。
    3.节点孩子的判断方式(w为v的邻接点,且w之前未被访问),
    回边的判断方式(w为v的邻接点,w已被访问)。
    4.DFSArticul函数同时实现visited数组的标记,low数组的更新与关节点的判定。

    时间复杂度分析:

    Tarjan算法的时间复杂度与图的深度优先遍历复杂度相同,都是对所有顶点与边访问一次,复杂度为O(V+E)。

    展开全文
  • //---连通图的关节点寻找算法及输出双连通分量---// //连通图的深度优先生成树中关节点特性: //1.若生成树的根有两棵或两棵以上的子树,则此根顶点必为关节点,因为图中不存在联结不同子树中顶点的边; //2.若生成...
    //---连通图的关节点寻找算法及输出双连通分量---//
    //连通图的深度优先生成树中关节点特性:
    //1.若生成树的根有两棵或两棵以上的子树,则此根顶点必为关节点,因为图中不存在联结不同子树中顶点的边;
    //2.若生成树中某个非叶子顶点,其某棵子树的结点均没有指向该结点的祖先的回边,则该结点必为关节点。
    //双连通分量:去掉任意一个结点都不会改变图的连通性,即不存在关节点
    //双连通分量算法:即求通过回边形成的环,在深度优先搜索树中,在回溯时,如果LOW[w]==DFN[v](w为v的邻接点),
    //则存在通过回边指向v的环。如果DFN[v]==LOW[v],则该点不存在于任何环中。
    #include <stdio.h>
    #include <stdlib.h>
    #include "AdjacencyList.h"
    typedef enum {FALSE,TRUE}Boolean;
    
    //栈结构和方法
    typedef struct
    {
        int st[MAX_VERTEX_NUM];
        int top;
    }Stack;
    void StackPush(Stack *S,int u);
    int StackPop(Stack *S);
    int StackEmpty(Stack S);
    Boolean IsArtic;
    
    int count;                          //计数已访问的点的数量,用于判断根结点是否为关节点
    int DFN[MAX_VERTEX_NUM];        //深度优先搜索树中点i访问的顺序
    int LOW[MAX_VERTEX_NUM];            //深度优先搜索树中点i所能回溯到的最浅层的点(如不能回溯,则为自己)
    Stack S;
    void FindArticul(ALGraph G);        //寻找关节点算法
    void DFSArticul(ALGraph G,int v,int f);   //从v点开始深度优先遍历寻找关节点
    
    int main()
    {
        ALGraph *G;
        G=(ALGraph *)malloc(sizeof(ALGraph));
    
        CreateGraph(G);
        int i,j;
        printf("图结构(邻接表表示):\n");
        for(i=0;i<G->vexnum;i++)
        {
            ArcNode *p;
            p=(ArcNode *)malloc(sizeof(ArcNode));
            p=G->vertices[i].firstarc;
            printf("%c ",G->vertices[i].data);
            while(p)
            {
                VertexType t;
                int k;
                k=p->adjvex;
                t=G->vertices[k].data;
                printf("%c ",t);
    
                p=p->nextarc;
            }
            printf("\n");
        }
        FindArticul(*G);
        return 0;
    }
    void FindArticul(ALGraph G)
    {
        IsArtic=FALSE;
        count=1;
        DFN[0]=LOW[0]=1;          //设定邻接表上0号顶点为生成树的根
        S.top=0;
    
        int i,v;
        for(i=1;i<G.vexnum;i++)
            DFN[i]=0;      //其余顶点初始化为未访问
    
        ArcNode *p;
        p=(ArcNode *)malloc(sizeof(ArcNode));
        p=G.vertices[0].firstarc;
        v=p->adjvex;        //第一个顶点的第一个邻接点
    
        DFSArticul(G,v,0);    //从第一个邻接点v点开始深度优先查找关节点
        if(LOW[v]==DFN[0])
        {
            int t;
    
            printf("\n双重连通分量:");
            while(!StackEmpty(S))
            {
                t=StackPop(&S);
                printf("%c ",G.vertices[t].data);
              }
             printf("%c ",G.vertices[0].data);
        }
    
        if(count<G.vexnum)  //即从第一个顶点的第一个邻接点出发进行深度遍历后,尚有点未被遍历到,则以顶点为根的搜索树有除第一个邻接点遍历形成的搜索子树外,还有其他搜索子树
        {
            IsArtic=TRUE;
            printf("\n关节点:%c \n",G.vertices[0].data);
            while(p->nextarc)
            {
                p=p->nextarc;
                v=p->adjvex;
                if(DFN[v]==0)   //第一个顶点的其他邻接点如果未被访问,则再从其开始进行深度优先遍历
                {
                    DFSArticul(G,v,0);
                    if(LOW[v]==DFN[0])
                    {
                        int t;
    
                        printf("\n%c出栈\n",G.vertices[t].data);
                        printf("\n双重连通分量:");
                        while(!StackEmpty(S))
                        {
                            t=StackPop(&S);
                            printf("%c ",G.vertices[t].data);
                        }
                         printf("%c ",G.vertices[0].data);
                    }
                }
            }
        }
        if(IsArtic==FALSE)
            printf("\n没有关节点!\n");
    }
    //---从v点开始进行深度优先遍历---//
    void DFSArticul(ALGraph G,int v,int f)
    {
        int min,w,current;
    
        DFN[v]=min=++count;   //表示结点v被访问的顺序,即count
    
        Boolean Articul;
        Articul=FALSE;
    
        ArcNode *p;
        p=(ArcNode *)malloc(sizeof(ArcNode));
        //for循环为继续深度优先遍历结点的邻接点
        for(p=G.vertices[v].firstarc;p;p=p->nextarc)
        {
            w=p->adjvex;        //v的邻接点w
            if(w!=f)
            {
                if(DFN[w]==0)
                {
                    current=S.top;        //对栈进行刻线,标记此刻栈中的状态
                    DFSArticul(G,w,v);    //如果未被访问,则再从它开始深度优先遍历
                    if(LOW[w]<min)
                        min=LOW[w];
    
                    if(LOW[w]==DFN[v])
                    {
                        int t;
    
                        printf("\n双重连通分量:");
                        while(S.top>current)
                        {
                            t=StackPop(&S);
                            printf("%c ",G.vertices[t].data);
                        }
                         printf("%c ",G.vertices[v].data);
                    }
                    if(LOW[w]>=DFN[v])
                        Articul=TRUE;   //如果存在子结点的LOW值不小于本结点的访问顺序值,则本结点为关节点
                }
                else if(DFN[w]<min)   //如果v的邻接点w已被访问,则意味着有往上的回边
                    min=DFN[w];
            }
        }
        //for循环结束即为完成邻接点的深度优先遍历,回溯到本结点
        if(Articul)
        {
            IsArtic=TRUE;
            printf("\n关节点:%c ",G.vertices[v].data);
        }
        LOW[v]=min;     //LOW[v]设定为子树(邻接点)中的最小值
    
        if(DFN[v]!=LOW[v])
            StackPush(&S,v);
    }
    void StackPush(Stack *S,int u)
    {
        S->st[S->top++]=u;
    }
    int StackPop(Stack *S)
    {
        return S->st[--S->top];
    }
    int StackEmpty(Stack S)
    {
        return S.top==0;
    }
    
    
    展开全文
  • 图的关节点 无向图,关于无向图的算法· 在c++主要源代码,向详细参考数据结构 c语言版
  • 连通图的关节点

    2019-12-06 12:13:55
    对树中任意节点V而言,其孩子结点为在他...2,若生成树中某个非叶子结点V,其某棵子树根和子树中其他结点都没有指向V祖先回边,则V为关节点。 辅助数组visited[v]值即为v在深度优先生成树前序序列中...
  • 直播带货app源码,连通图的关节点相关的代码 #include<stdio.h> #include<stdlib.h> #define ERROR 0 #define OK 1 #define MAX_VERTEX_NUM 20 typedef int Status; typedef char VertexType; ...
  • 图的关节点算法实现

    千次阅读 2018-11-27 13:32:45
    重连通:没有关节点的图,在重连通中任意两点之间至少存在两条路径 关节点求法:算法较难理解,算法结合了先序深度搜索和后序深度搜索,先序深度搜索确定每个点访问顺序,而后序深度搜索则根据先序计算顺序...
  • C++代码,数据结构-连通图的关节点

    千次阅读 2014-01-17 22:34:03
    连通图的关节点,按照书上使用邻接表的作为图的储存, #include #include using namespace std; //图的邻接表的表示 #define max_ver 20 struct Arcnode{ int adjvex; //该弧所指向顶点的位置 Arcnode *nextarc; }; ...
  • 数据结构 || 求连通图的关节点

    千次阅读 2019-01-23 15:06:21
    假若在删去顶点v以及v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连通分量,则称顶点v为该图的一个关节点。 如果没有关节点的连通图则称为重连通图(双连通图)。 算法实现: 1. 方法一: 最简单也是...
  • 求无向图的关节点算法

    千次阅读 2011-04-18 15:57:00
    求无向的图的关节点的这个算法是我觉得比较难理解的算法之一,我觉得难并不是难在算法本身,而是难在该算法的递归的实现上,特别是在DFSArticul()递归退出以后才可以进行low[]函数的计算,这点,如果是在自己独立...
  • 倘若在删去顶点v以及v相关联的各边后,将图的一个连通分量分割成两个或两个以上的分量,则称顶点v为该图的一个关节点 关节点的特性 由深度优先生成树可得出两类关节点的特性: 若生成树的根有两棵或两棵以上的子树...
  • 关节点(Articulation Poinst)是指,在原本连通的图,在删除关节点及依附边之后,将被分割成至少两个连通分量(原本整连通的图变得不连通)。 另外,没有一个关节点的连通称为双连通(Biconnect Graph) 二、求解...
  • //图的邻接表表示 //弧节点 class GraphArcNode { private: int weight; int adjVertexIndex; GraphArcNode* nextArcNode; public: GraphArcNode(int d = 0, int index = 0) { weight = d; adjVerte
  • 求解无向连通图的关节点

    千次阅读 2012-07-05 23:31:13
    2.任何其它顶点u是关节点的充要条件是u至少有一个子女w,使得经过只由w,w后代以及一条回边构成路径不可能到达u祖先,因为删除顶点u及其关联边将使w及其后代与u祖先断开联系。  假设顶点w祖先包括w...
  • 第7章 图 -无向图的关节点 ——《数据结构》-严蔚敏.吴伟民版 源码使用说明 链接☛☛☛ 《数据结构-C语言版》(严蔚敏,吴伟民版)课本源码+习题集解析使用说明 课本源码合辑 链接☛☛☛ 《数据结构》课本源码合...
  • 求连通图的关节点(割点)--C语言

    千次阅读 2017-01-21 19:51:20
    最简单也是最直接的算法是,删除一个然后判断连通性,如果删除此,图不再连通,则此是割点,反之不是割点(图的连通性一般通过深搜来判定,是否能一次搜索完 全部顶点); 通过深搜优先生成树来判定。从任一点...
  • 链接 :  ... 题意 : 一个有向,如果从0出发到达某一点必须...点数不多 可以删然后dfs搜索,之前能搜到的点 但是删了该之后搜不到了 那么这个删就是从起始搜不到必经之路。 #include #

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 627
精华内容 250
关键字:

图的关节点