無向連通圖點雙連通分量

Enjoy_process發表於2018-09-04

定義:

無向連通圖點雙連通分支是指不包含割點的極大連通子圖 

割點可以屬於多個點雙連通分支,其餘點和每條邊只屬於且屬於一個點雙連通分支。

無重邊的無向連通圖點雙連通分支 

//無重邊的無向連通圖點雙連通分支 
#include<iostream>
#include<vector>
#include<stack> 

using namespace std;
const int N=200;
vector<int>g[N];
int dfn[N],low[N];
int index,n,m;//index編號 n點數 m邊數
struct Edge{
	int u,v;
	Edge(int u,int v):u(u),v(v){}
};
stack<Edge>s;
int t;

void Tarjan(int u,int father)//father是u的父節點 
{
	dfn[u]=low[u]=index++;
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(!dfn[v]){//v沒有被訪問
		    //樹邊入棧
			s.push(Edge(u,v)); 
			Tarjan(v,u);
			low[u]=min(low[u],low[v]);
			Edge temp(0,0);
			if(dfn[u]<=low[v]){
/*從一條邊往下走,走完後發現自己是割點,則棧中的邊一定全是和自己在一個雙  
  連通分量裡面,根節點總是和其下的某些點在同一個雙連通分量裡面 
*/				cout<<"Block No:"<<++t<<endl;
				do{
					temp=s.top();
					s.pop();
					cout<<temp.u<<","<<temp.v<<endl;
				}while(!(temp.u==u&&temp.v==v));	
			}
		}
		else if(father!=v){//連到父節點的回邊不考慮
			low[u]=min(low[u],dfn[v]); 
//連線到祖先的回邊要入棧,但是連線到兒子的邊,此處肯定已經入過棧了 
			if(dfn[u]>dfn[v]) 
			  s.push(Edge(u,v));
		}
	} 
}

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);
	} 
	Tarjan(1,0); 
	return 0;
 } 

 

相關文章