Tarjan (橋和割點模板)

補習Tarjan

割點

    定義:若從圖中刪除節點 x 以及所有與 x 關聯的邊之後,圖將被分成兩個或兩個以上的不相連的子圖,那麼稱 x 爲圖的割點。

    如何求割點:在深搜樹中,如果對於某個點u,與它相連的點v(v不是u的父親)。

                         那麼如果 low[v]>=dfn[u] , 那麼也就是以v爲根的深搜子樹中的點所連接的點沒有已經標記時間戳的。

                         也就是以v爲根的子樹是封閉的,那麼一旦去掉點u,這棵子樹中的點就稱爲了一個新的連通分量。

                         那麼點u就是割點了。

    割點的判斷:

                        1)如果這個點時根節點,並且兒子>=2則這個點就是割點 
                        2)對於點U存在子節點V,V可以訪問到U的父節點,那麼點U就不是割點,否則就是割點

 

模板:

const int MAXN = 1e5;
int head[MAXN], cnt, tot, dfn[MAXN], low[MAXN];
int root; 
int n, m;
set<int> ans;
struct Edge{
	int to, dis, next;
}edge[MAXN << 1];
void add_edge(int u, int v, int dis) {
	edge[++cnt].to = v;
	edge[cnt].dis = dis;
	edge[cnt].next = head[u];
	head[u] = cnt;
}
void init() {
	cnt = 1;
	tot = 0;
	memset(head, 0, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	ans.clear();
}
void Tarjan(int x, int fa) {
	low[x] = dfn[x] = ++tot;
	int son = 0;
	for (int i = head[x]; i; i = edge[i].next) {
		int to = edge[i].to;
		if(to == fa) continue;	//因爲是無向圖所以把回邊給跳過了 
		if (!dfn[to]) {
			Tarjan(to, x);
			low[x] = min(low[x], low[to]); 
			son++;
			if ( x == root && son > 1) {	//如果這個點時根節點,並且兒子>=2則這個點就是割點 
				ans.insert(x);
			} else if (x != root && dfn[x] <= low[to] ) { //對於點U存在子節點V,V可以訪問到U的父節點,那麼點U就不是割點,否則就是割點
				ans.insert(x);
			}
		} else {
			low[x] = min(low[x], dfn[to]); 
		}
	}
}

add_edge(u, v, 0);

for (int i = 1; i <= n; ++i) {
	if (!dfn[i]){
		root = i;
		Tarjan(i, i);
	}
}

專題:

POJ1144 (模板題求割點)

    定義:若從圖中刪除邊 e 之後,圖將分裂成兩個不相連的子圖,那麼稱 e 爲圖的橋或割邊。

    如何求橋:在一張無向圖中,判斷邊 e (其對應的兩個節點分別爲 u 與 v)是否爲橋,

                      需要其滿足如下條件即可:dfn[u] < low[v]

                      我們發現從v節點出發,在不經過(u, v)的前提下,不管走哪一條邊,

                      我們都無法抵達u節點,或者比u節點更早出現的節點,

                      此時我們發現v所在的子樹似乎形成了一個封閉圈,那麼(u, v)自然也就是橋了. 

模板:

#include<set>
#define LL long long
#define P pair<int, int>
using namespace std;
const int MAXN = 1e5 + 10;
int head[MAXN], cnt, dfn[MAXN], low[MAXN], tot;
set<P> ans;
struct Edge{
	int to, dis, next;
}edge[MAXN << 1];
void add_edge(int u, int v, int dis) {
	edge[++cnt].to = v;
	edge[cnt].dis = dis;
	edge[cnt].next = head[u];
	head[u] = cnt; 
}
void Tarjan (int x, int fa) {
	low[x] = dfn[x] = ++tot;
	for(int i = head[x]; i; i = edge[i].next) {
		int to = edge[i].to;
		if(to == fa) continue;	//因爲是無向圖所以把回邊給跳過了 
		if(!dfn[to]) {	//沒搜過 
			Tarjan(to, x);
			low[x] = min(low[x], low[to]);
			if(dfn[x] < low[to]) {	//這條連線是關鍵線 
				ans.insert(make_pair(min(x, to), max(x, to)));    //小的在前
			}
		} else {	//搜過了,改當前的最短時間戳的值 
			low[x] = min(low[x], dfn[to]);	
		} 
	}
}
void init() {
	cnt = 1;
	tot = 0;
	memset(head, 0, sizeof(head));
	memset(dfn, 0, sizeof(dfn));
	memset(low, 0, sizeof(low));
	ans.clear();
}

add_edge(u, v, 0);

for (int i = 0; i < n; ++i) {
	if(!dfn[i])
	    Tarjan(i, i);
}

專題:

UVA-796 (橋的模板題)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章