zoukankan      html  css  js  c++  java
  • 【编程题目】求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边, 有向图不再连通

    39.(树、图、算法)
    (2).
    求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边,
    有向图不再连通,描述算法。

    思路:这里有个问题,对于图的连通性,我默认它要求强连通。采用了最简单的办法,即每次删掉一条边,判断图还是否连通。若变得不连通了就认为此点是割点。

    连通性的判断也采用了直觉上简单的方法,就是对每一个点判断是否有向内指向它的边和它向外指向的边。(question:如此直观的方法是否会有错呢?)

    /*
    39.(树、图、算法)
    (2).
    求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边,
    有向图不再连通,描述算法。
    */
    
    #include <stdio.h>
    
    #define MAX_VERTEX_NUM 20
    #define INFINITY 10000
    
    typedef struct ArcCell{
        int adj;
    }ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    
    typedef struct MGraph{
        int vexs[MAX_VERTEX_NUM];
        AdjMatrix arcs;
        int vexnum, arcnum;
    }MGraph;
    
    //定位顶点
    int LocateVex(MGraph G, int v)
    {
        for(int i = 0; i < G.vexnum; i++)
        {
            if(G.vexs[i] == v)
                return i;
        }
        return -1; //means error
    }
    void CreateDN(MGraph &G) //生成有向图
    {
        printf("Input the vexnum:");
        scanf("%d",&G.vexnum);
        printf("Input the arcnum:");
        scanf("%d", &G.arcnum);
    
        for(int i = 0; i < G.vexnum; i++)
        {
            printf("Input the %d vex:", i);
            scanf("%d", &G.vexs[i]);
        }
    
        for(int i = 0; i < G.vexnum; i++)
            for(int j = 0; j < G.vexnum; j++)
                G.arcs[i][j].adj = INFINITY;
    
        for(int k = 0; k < G.arcnum; k++)
        {
            int v1, v2, w;
            printf("input the arcs vex and weight:");
            scanf("%d %d %d", &v1, &v2, &w);
            int i = LocateVex(G, v1);
            int j = LocateVex(G, v2);
            G.arcs[i][j].adj = w;
        }
    }
    
    //有向图是否强连通
    bool isConnected(MGraph G)
    {
        bool connected = true;
        for(int i = 0; i < G.vexnum; i++)
        {
            bool haveConnectedIn = false;
            bool haveConnectedOut = false;
            for(int j = 0; j < G.vexnum; j++)
            {
                if(G.arcs[i][j].adj < INFINITY)
                    haveConnectedOut = true;
                if(G.arcs[j][i].adj < INFINITY)
                    haveConnectedIn = true;
            }
    
            if(haveConnectedOut != true || haveConnectedIn != true)
            {
                connected = false;
                break;
            }
        }
    
        return connected;
    }
    
    //得到有向图G去掉一个顶点和其相邻边后的图
    MGraph deleteOneVex(MGraph G, int vex)
    {
        MGraph DG;
        DG.vexnum = G.vexnum - 1;
        int j = 0;
        for(int i = 0; i < G.vexnum; i++)
        {
            if(i != vex)
            {
                DG.vexs[j++] = G.vexs[i]; 
            }
        }
    
        DG.arcnum = 0;
        for(int i = 0; i < G.vexnum; i++)
            for(int j = 0; j < G.vexnum; j++)
                if(i != vex && j != vex)
                {
                    int v = (i > vex) ? i - 1 : i;
                    int u = (j > vex) ? j - 1 : j;
                    DG.arcs[v][u].adj = G.arcs[i][j].adj;
                    DG.arcnum++;
                }
    
        return DG;
    }
    
    //查找图的割
    void GetGutSet(MGraph G)
    {
        bool isconnect = isConnected(G);
        if(isconnect == false)
        {
            printf("the Graph is not connected.
    ");
            return;
        }
    
        int n = 0;
        if(G.vexnum < 1)
        {
            printf("no vex");
        }
        else if(G.vexnum == 1)
        {
            printf("cut is %d
    ", G.vexs[0]);
        }
        else
        {
            for(int i = 0 ; i < G.vexnum; i++)
            {
                MGraph DG = deleteOneVex(G, i);
                bool isconnect = isConnected(DG);
                if(isconnect == false)
                {
                    printf("The %d cut vex is %d
    ", n, G.vexs[i]);
                }
            }
        }
    }
    
    int main()
    {
        MGraph G;
        CreateDN(G);
        GetGutSet(G);
    
        return 0;
    }

    网上看到有专门的算法,还在学习。

    找到一个求无向图割点的:

    http://www.cnblogs.com/mfryf/archive/2012/08/23/2652102.html

    通过深搜优先生成树来判定。从任一点出发深度优先遍历得到优先生成树,对于树中任一顶点V而言,其孩子节点为邻接点。由深度优先生成树可得出两类割点的特性:

         (1)若生成树的根有两棵或两棵以上的子树,则此根顶点必为割点。因为图中不存在连接不同子树顶点的边,若删除此节点,则树便成为森林;

         (2)若生成树中某个非叶子顶点V,其某棵子树的根和子树中的其他节点均没有指向V的祖先的回边,则V为割点。因为删去v,则其子树和图的其它部分被分割开来。

    仍然利用深搜算法,只不过在这里定义visited[v]表示为深度优先搜索遍历图时访问顶点v的次序号,定义low[v]=Min{visited[v],low[w],visited[k]},其中w是顶点v在深度优先生成树上的孩子节点;k是顶点v在深度优先生成树上由回边联结的祖先节点。

       割点判定条件:如果对于某个顶点v,存在孩子节点w且low[w]>=visited[v],则该顶点v必为关节点。因为当w是v的孩子节点时,low[w]>=visited[v],表明w及其子孙均无指向v的祖先的回边,那么当删除顶点v后,v的孩子节点将于其他节点被分割开来,从来形成新的连通分量。

    #include <iostream>  
    2.#include <string>  
    3.using namespace std;  
    4.  
    5.#define MAX_VERTEX_NUM 13  
    6.  
    7.//邻接表存储结构  
    8.typedef struct ArcNode{  
    9.    int adjvex;  
    10.    ArcNode *nextarc;  
    11.}ArcNode;  
    12.  
    13.typedef struct VNode{  
    14.    string data;  
    15.    ArcNode* firstarc;  
    16.}VNode,AdjList[MAX_VERTEX_NUM];  
    17.  
    18.typedef struct{  
    19.    AdjList vertices;  
    20.    int vexnum, arcnum;  
    21.}ALGraph;  
    22.  
    23.//返回u在图中的位置  
    24.int LocateVex(ALGraph G, string u)  
    25.{  
    26.    for(int i=0; i<G.vexnum; i++)  
    27.        if(G.vertices[i].data==u)  
    28.            return i;  
    29.    return -1;  
    30.}  
    31.  
    32.//构造图  
    33.void CreateDG(ALGraph &G)  
    34.{  
    35.    string v1, v2;  
    36.    int i, j, k;  
    37.    cout<<"请输入顶点数和边数:";  
    38.    cin>>G.vexnum>>G.arcnum;  
    39.  
    40.    cout<<"请输入顶点:";  
    41.    for(i=0; i<G.vexnum; i++)  
    42.    {  
    43.        cin>>G.vertices[i].data;  
    44.        G.vertices[i].firstarc=NULL;  
    45.    }  
    46.  
    47.    cout<<"请输入边:"<<endl;  
    48.    for(k=0; k<G.arcnum; k++)  
    49.    {  
    50.        cin>>v1>>v2;  
    51.        i=LocateVex(G, v1);  
    52.        j=LocateVex(G, v2);  
    53.  
    54.        //无向图  
    55.        ArcNode *arc=new ArcNode;  
    56.        arc->adjvex=j;  
    57.        arc->nextarc=G.vertices[i].firstarc;  
    58.        G.vertices[i].firstarc=arc;  
    59.  
    60.        arc=new ArcNode;  
    61.        arc->adjvex=i;  
    62.        arc->nextarc=G.vertices[j].firstarc;  
    63.        G.vertices[j].firstarc=arc;  
    64.    }  
    65.  
    66.}  
    67.  
    68.//求割点  
    69.int count ;  
    70.int visited[MAX_VERTEX_NUM];  
    71.int low[MAX_VERTEX_NUM];  
    72.  
    73.//从第v0个顶点出发深搜,查找并输出关节点(割点)  
    74.void DFSArticul(ALGraph G, int v0)  
    75.{  
    76.    int min, w;  
    77.    ArcNode *p;  
    78.    visited[v0]=min=++count;//v0是第count个访问的顶点,min的初值为visited[v0],即v0的访问次序  
    79.  
    80.    for(p=G.vertices[v0].firstarc; p ; p=p->nextarc)  
    81.    {  
    82.        w=p->adjvex;  
    83.        if(visited[w]==0)//w未曾访问,是v0的孩子  
    84.        {  
    85.            DFSArticul(G, w);//从第w个顶点出发深搜,查找并输出关节点(割点),返回前求得low[w]  
    86.            if(low[w]<min)//如果v0的孩子节点w的low[]小,说明孩子节点还与其他节点(祖先)相邻  
    87.                min=low[w];  
    88.            if(low[w]>=visited[v0])//v0的孩子节点w只与v0相连,则v0是关节点(割点)  
    89.                cout<<G.vertices[v0].data<<" ";  
    90.        }  
    91.        else if(visited[w]<min)//w已访问,则w是v0生成树上祖先,它的访问顺序必小于min  
    92.            min=visited[w];  
    93.    }  
    94.  
    95.    low[v0]=min;//low[v0]取三者最小值  
    96.      
    97.}  
    98.  
    99.void FindArticul(ALGraph G)  
    100.{  
    101.    int i, v;  
    102.    ArcNode *p;  
    103.    count=1;  
    104.    visited[0]=1;//从0号节点开始  
    105.    for(i=1; i<G.vexnum; i++)  
    106.        visited[i]=0;  
    107.    p=G.vertices[0].firstarc;  
    108.    v=p->adjvex;  
    109.    DFSArticul(G, v);  
    110.    if(count<G.vexnum)  
    111.    {  
    112.        cout<<G.vertices[0].data<<" ";  
    113.        while(p->nextarc)  
    114.        {  
    115.            p=p->nextarc;  
    116.            v=p->adjvex;  
    117.            if(visited[v]==0)  
    118.                DFSArticul(G, v);  
    119.        }  
    120.    }  
    121.}  
    122.  
    123.void main()  
    124.{  
    125.    ALGraph g;  
    126.    CreateDG(g);  
    127.  
    128.    cout<<"割点如下: "<<endl;  
    129.    FindArticul(g);  
    130.    cout<<endl;  
    131.}  
  • 相关阅读:
    git commit 合并
    git 管理 Linux 文件系统
    python 全局变量的使用
    JavaScript 中 类型转换
    canconfig 配置命令
    python 调用 shell 命令
    python 3 操作mysql数据库的方法
    python 字符串和整数,浮点型互相转换
    JavaScript 里面的整数 位 操作
    JavaScript 使用 php 的变量
  • 原文地址:https://www.cnblogs.com/dplearning/p/3992097.html
Copyright © 2011-2022 走看看