1. 程式人生 > >圖論:割點和橋

圖論:割點和橋

刪除 bsp find cin return inf gif pri 記錄

一、相關概念

1、點連通度:最小V的點數(一個圖的點的連通度是最小割點集合中的頂點數)

2、邊連通度:最小E的邊數(一個圖的邊的連通度是最小割邊集合中的頂點數)

3、割點:去掉割點這個圖不連通(點連通度為1時,V的唯一元素)

4、割邊(橋):去掉割邊這個圖不連通(邊連通度為1時,E的唯一元素)

5、雙連通圖:

如果一個無向圖的點連通度大於1,則是點雙聯通;

如果一個無向圖的邊連通度大於1,則是邊雙聯通。

6、雙聯通分量:

在圖G中,G’是G的子圖,G’雙聯通,則G’是雙聯通分量。

(雙聯通分量一定是點雙聯通分量,但不一定是邊雙聯通分量)

7、雙連通性:將無向圖的任意頂點刪除後,剩下的圖依然連通,那麽這樣的圖是雙聯通的。

二、割點的求解方法

1、無向圖的深度優先生成樹:

將對無向圖進行深度優先遍歷的順序作為樹節點的編號,建立正向邊;

相反的,如果遍歷到已經存在的節點,建立相應的背向邊。

2、求解割點的過程:

(1)建立Num(v),按照深搜的順序給節點編號(先序遍歷編號)

(2)建立Low(v)的三原則:(後序遍歷)

Num(v);

所有背向邊(v,w)中最低的Num(w);

所有邊(v,w)中最低的Low(w);

(3)割點的條件

如果是根節點:有一個以上的兒子;

如果不是根節點:Low(v)>= Num(v)。

(具體實現的細節:

(1)可以讓根節點就是割點然後建立深搜樹,再求割點;

(2)也可以記錄每個節點的兒子的數量然後分別判斷根節點與非根節點)。

3、實現:

技術分享圖片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 1200;
const int INF = 0x3ffffff;
int num[maxn],parent[maxn],low[maxn],vis[maxn],cnt;
vector <int> vc[maxn];
int MIN(int x,int y)
{
    return x<y?x:y;
}
void AssignNum(int v) //建立dfs深搜樹 { int i,w; num[v]=cnt++; vis[v]=1; for(i=0;i<vc[v].size();i++){ w=vc[v][i]; if(vis[w]==0){ parent[w]=v; AssignNum(w); } } } void AssignLow(int v) //建立low數組,打印割點 { int i,w; low[v]=num[v]; for(i=0;i<vc[v].size();i++){ w=vc[v][i]; if(num[w]>num[v]){ AssignLow(w); if(low[w]>=num[v]){ printf("The gedian is %d\n",v); } low[v]=MIN(low[v],low[w]); } else if(parent[v]!=w){ low[v]=MIN(low[v],num[w]); } } } void FindArt(int v) //打印割點 = AssignNum+AssignLow; { int i,w; low[v]=num[v]=cnt++; vis[v]=1; for(i=0;i<vc[v].size();i++){ w=vc[v][i]; if(!vis[w]){ parent[w]=v; FindArt(w); if(low[w]>=num[v]) printf("The articulation point is %d\n",v); low[v]=MIN(low[v],low[w]); } else if(parent[v]!=w) low[v]=MIN(low[v],num[w]); } } int main(void) { int n,m,i,j,x,y; cin>>n>>m; cnt=1; memset(vis,0,sizeof(vis)); for(i=0;i<m;i++){ scanf("%d%d",&x,&y); vc[x].push_back(y); vc[y].push_back(x); } //AssignNum(3); //AssignLow(3); FindArt(4); //根節點是割點 return 0; } /* 7 8 1 2 2 3 3 4 4 1 4 7 4 5 7 5 3 6 */
View Code

三、橋的求解方法

一條無向邊(u,v)是橋當且僅當(u,v)是深搜樹的樹枝邊且滿足Num(u)< Low(v)。

            if(num[v]<low[w]) printf("---The edge (%d,%d) is artedge\n",v,w);  //求割邊 

圖論:割點和橋