無向連通圖求割點和橋

Enjoy_process發表於2018-09-04

定義

無向連通圖中,如果刪除某點後,圖變成不連通,則稱該點為割點

無向連通圖中,如果刪除某邊後,圖變成不連通,則稱該邊為橋

無重邊的無向連通圖求割點和橋

dfn[i]表示編號為i的節點在DFS過程中的訪問序列(也可以叫做開始時間)。在DFS過程中會形成一搜尋樹。在搜尋樹上越先遍歷到的節點,dfn值越小

low[i]定義為i或者i的子樹中能夠通過非父子邊追溯到的最早的節點的DFS開始時間。

一個頂點u是割點,當且僅當滿足(1)或(2)

(1)u為樹根,且u有多於一個子樹

(2)u不為樹根,且存在(u,v)為樹枝邊(或稱父子邊,即u為v在搜尋樹中的父親),使得dfn[u]<=low[v]

非樹枝邊不可能是橋

一條邊(u,v)是橋,當且僅當(u,v)為樹枝邊,且滿足dfn[u]<low[v](前提是沒有重邊)

//無重邊的無向連通圖求割點和橋
#include<iostream>
#include<vector>

using namespace std;
const int N=200;
vector<int>g[N];
int dfn[N],low[N],pre[N];
bool flag[N];//記錄每個點是否為割點 
int index,n,m;//index編號 n點數 m邊數

void Tarjan(int u,int father)//father是u的父節點 
{
	pre[u]=father;
	dfn[u]=low[u]=index++;
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(!dfn[v]){
			Tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else if(father!=v)//連到父節點的回邊不考慮,否則求不出橋
			low[u]=min(low[u],dfn[v]); 
	} 
}

void Count()
{//計算割點和橋 
	int num=0;
	Tarjan(1,0);
	for(int i=2;i<=n;i++){
		int v=pre[i];
		if(v==1)
		  num++;//DFS樹中根節點有幾個子樹
		else if(dfn[v]<=low[i])
		  flag[v]=true; 
	}
	if(num>1)
	  flag[1]=true;
	for(int i=1;i<=n;i++)
	  if(flag[i])
	    cout<<i<<endl;
	for(int i=1;i<=n;i++){
		int v=pre[i];
		if(v>0&&dfn[v]<low[i])
		  cout<<v<<","<<i<<endl;
	} 
}

int main()
{
	int u,v;
	index=1;
	cin>>n>>m;//點數 邊數
	for(int i=1;i<=m;i++){
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	} 
	Count();
	return 0;
 } 

 

相關文章