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

来源:互联网 发布:php企业站 编辑:程序博客网 时间:2024/05/29 07:33


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

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


求割点的伪代码

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 ifInit() :  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;}


0 0