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

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.\n");

        return;

    }



    int n = 0;

    if(G.vexnum < 1)

    {

        printf("no vex");

    }

    else if(G.vexnum == 1)

    {

        printf("cut is %d\n", 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", 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.}  

 

你可能感兴趣的:(编程)