求无向图的割点 (poj 1144 Network)


割点 :去掉该点后原来的图不连通(出现好几个连通分量),该点被称为割点。

注意删除某点意味着和该点关联的边也全部删除


求割点的伪代码

DFS(v1,father):
  dfn[v1] = low[v1] = ++dfsClock
  vis[v1] = true
  child = 0
  for each egde(v1,v2) in E:
    if(vis[v2] == false) : //(v1,v2)是父子边
        DFS(v2,v1)
       child++
        low[v1] = Min(low[v1],low[v2])
        if(v1 != root && low[v2] >= dfn[v1])
            v1 is cut point
        if(low[v2] > dfn[v1])
            edge(v1,v2) is bridge
    end if
    elseif(v2 != father && vis[v2] == true) : //v2已经被访问过,(v1,v2)是反向边
        low[v1] = Min(low[v1],dfn[v2])//此时要更新low[v1]
    end if

Init() :
  dfn[] = low[] = vis[] = 0
  dfsClock = 0



dfn【i】 记录 DFS树的深度,也就是,DFS中第几次遍历到的点,dfn的值就为几;

low【i】存储的是 i节点及i节点的后续节点通过反向边所能达到的最小的DFS深度

【更新low】

如果所处的边是树边,low【v1】=min(low【v1】,low【v2】)

如果所处的边是反向边,low【v1】=min(low【v1】,dfn【v2】)

【判断割点】

假设v2是v1的子节点

如果v1是根节点, 那么如果v1有两个或者两个以上的子节点,那么v1是割点

如果v1不是根节点,那么如果low【v2】 >=dfn【v1】,可以判断 v1是割点。


给个模板题 poj1144 network


题目链接:http://poj.org/problem?id=1144

【题目大意】

Telephone Line Company 在城市与城市之间建立了电话网络,有这样一种城市S, 如果S的电话服务崩溃了,那么 其他城市的电话并不能联通(就是至少有一个城市其他城市都连接不到)。

给你城市 与城市之间的关系, 找出有多少个 这样的城市 S;

典型的模板题, S就是图中的 割点

【源代码】

#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
const int maxn =110;
vector<int>G[maxn]; //用邻接链表存图
int dfn[maxn],low[maxn],dfsClock;
bool cutNode[maxn]; //记录是否为割点
int vis[maxn];
void DFS(int v1,int father){
	int child =0;
	vis[v1]=true;
	dfn[v1]=low[v1]= ++dfsClock;
	for(int i=0;i<G[v1].size();i++){
		int v2=G[v1][i];
		if(!vis[v2]){
			DFS(v2,v1);
			child++;
			low[v1] = min(low[v1],low[v2]);
			if(v1 != 1 && low[v2] >= dfn[v1]) //割点
				cutNode[v1]=true;
			if(v1 == 1 &&child >=2){ //如果是起点 
				 cutNode[v1]=true;
			}
		}
		else if(vis[v2]&&v2!=father){ //如果是 反向边 
			low[v1]=min(low[v1],dfn[v2]);
		}
	}
}
void init(){
	for(int i=0;i<maxn;i++){
		G[i].clear();
		dfn[i]=low[i]=0;
		cutNode[i]=0;
		vis[i]=0;
	}
	dfsClock = 0;
}
int main(){
	int n;
	while(scanf("%d",&n)!=EOF&&n){
		init();
		int tmp;char c;
		int v1,v2;
		while(scanf("%d",&v1)&&v1){
			while((c=getchar())!='\n'){
				scanf("%d",&v2);
				G[v1].push_back(v2);
				G[v2].push_back(v1);
			}
		}
		DFS(1,-1);
		int ans=0;
		for(int i=1;i<=n;i++){
			if(cutNode[i])
				ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}


你可能感兴趣的:(算法,图论,求割点)