图论之割点和桥

割点:如果在图G中删去一个结点u后,图G的连通分枝数增加,即W(G-u)>W(G),则称结点u为G的割点,又称关节点。
桥:如果在图G中删去一条边e后,图G的连通分支数增加,即W(G-e)>W(G),则称边e为G的桥,又称割边或关节边。

双连通分支:G中不含割点的极大连通子图称为G的双连通分支,又称为G的块。

例子:给定一个无向图,找出图中的割点和桥

说明:节点用v表示

Vis[v]:记录节点v当前的访问状态:1表示在栈中,0表示未

访问,2表示已经访问过

Dfn[v]:记录节点v被访问时的深度

Low[v]:记录节点v可以到达的访问时间最早的祖先

在深度遍历图的过程中,记录下每个节点的深度,对当前节点cur,以及和它相连的点i,有两种情况:

(1)i没有·被访问过,这时递归访问节点i,并用i可以到达的最早的祖先来更新cur的low值。

(2)i在栈中这是说明图中有一个环,用i的深度更新cur的low值。

cur是割点的条件:cur是根且有大于一个的儿子,或者cur不是根,且cur有一个儿子v,使得low[v]>=dfn[cur]

(cur,i)是桥的条件:low[i]>dfn[cur]

void CutBridge(int cur, int father, int dep, int n){
	//可设为全局变量
	const int V = 1000;
	int edge[V][V];
	int bridge[V][V], cut[V];
	int low[V], dfn[V], vis[V];
	vis[cur] = 1; dfn[cur] = low[cur] = dep;
	int children = 0;
	for (int i = 0; i < n; ++i)if (edge[cur][i]){
		if (i != father && 1 == vis[i]){
			if (dfn[i] < low[cur])
				low[cur] = dfn[i];//用i被访问时的深度来更新cur的low值
		}
		if (0 == vis[i]){
			CutBridge(i, cur, dep + 1, n);//递归访问节点i
			children++;
			if (low[i] < low[cur])low[cur] = low[i];
			if ((father == -1 && children > 1) || (father != -1 && low[i] >= dfn[cur]))
				cut[cur] = true;
			if (low[i] > dfn[cur]){ bridge[cur][i] = bridge[i][cur] = true; }
		}
	}
	vis[cur] = 2;
}


你可能感兴趣的:(C++,图论)