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

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.}  

 

posted @ 2014-09-25 09:39  匡子语  阅读(2772)  评论(0编辑  收藏  举报