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 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
#define LL long long
#define P pair
using namespace std;
const int MAXN = 1e5 + 10;
int head[MAXN], cnt, dfn[MAXN], low[MAXN], tot;
set

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 (桥的模板题)

 

你可能感兴趣的:(Tarjan)