【編程題目】求一個有向連通圖的割點,割點的定義是,如果除去此節點和與其相關的邊, 有向圖不再連通


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM