一.图的割点
先解释一下什么叫图的割点吧,割点就是如果去掉这个点之后无法实现所有点的相互连通,那么这个点就是割点。
二.寻找图的割点
那么给定一张图怎么找到图的割点呢,当然了,所谓割点当然应该是一个图里只有一个强联通分量吧,那么说一下我们大致的算法,我们判断一个节点u是否是割点,就是判读他的子节点中是否存在节点不经过这个节点就无法回到祖先,如果是这样的,那么这个节点就是割点。我们用dfn[u]来记录访问到u的时间戳,low[u]来记录u节点在不经过其父节点所能访问到的最早时间戳(就是第一个能够访问到的祖先节点编号),有了这两个数据,那么根据我们上面的算法我们知道如果
low
[i]>=
num
[cur](i是cur的子节点
),那么也就是说i没法回到祖先,所以说cur应该是割点
三.数据
n个点m个边,无向图
6 7
1 3
1 4
4 2
3 2
2 5
2 6
5 6
//
// main.cpp
// 图的割点
//
// Created by 张嘉韬 on 16/8/29.
// Copyright © 2016年 张嘉韬. All rights reserved.
//
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=1000;
int min(int a,int b)
{
if(a<b) return a;
else return b;
}
int map[maxn][maxn],n,m,x,y,root,flag[maxn],indx,num[maxn],low[maxn];
void dfs(int cur,int father)
{
int child=0;
indx++;
num[cur]=indx;
low[cur]=indx;
for(int i=1;i<=n;i++)
{
if(map[cur][i]==1)
{
if(!num[i])
{
dfs(i,cur);// 子节点就去dfs()
low[cur]=min(low[cur],low[i]);
if(cur!=root&&low[i]>=num[cur]) flag[cur]=1;
if(cur==root&&child==2) flag[cur]=1;//虽然未遍历完但是如果有两个两个子节点了那么一定就是割点。
}
else if(num[i]&&i!=father)
low[cur]=min(num[i],low[cur]);
}
}
}
int main(int argc, const char * argv[]) {
freopen("/Users/zhangjiatao/Documents/暑期训练/input.txt","r",stdin);
memset(map,0,sizeof(map));
memset(flag,0,sizeof(flag));
memset(num,0,sizeof(num));
memset(low,0,sizeof(low));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
map[x][y]=1;
map[y][x]=1;
}
root=1;
indx=0;
dfs(1,root);
for(int i=1;i<=n;i++) cout<<num[i]<<" ";
cout<<endl;
for(int i=1;i<=n;i++) cout<<low[i]<<" ";
cout<<endl;
for(int i=1;i<=n;i++)
if(flag[i]) printf("%d\n",i);
return 0;
}