连通图求割点
割点
总结一下连通图,在连通网络中,有一些点是这个图中的必经之点,所以这个点是一个很重要的点,我们称为割点
例如 这个无向连通图:
1----2----3----4----5
这个直线中有三个割点(2,3,4)
,失去其中任意一个点,这个图的整体就会失去整体的连通性
如何求割点
1:如果某点是根节点,而且它有(m>1)
个子节点,呢么他是一个割点
2:如果某个点是某个连通图中的必经之点,若用low[ ]和dfn[ ]
表示的话low[u]>=dfn[v]
,呢么v
是一个割点
分部代码:
首先预处理一下low[ ]和dfn[ ]
的关系
void dfs(int u,int fa)fa是u的父节点
{
low[u]=dfn[u]=++times;//次序和时间戳
father[u]=fa;
int len=vec[u].size();
for(int i=0;i<len;i++)
{
int v=vec[u][i];
if(!dfn[v])
{
dfs(v,u);//儿子和父亲
low[u]=min(low[u],low[v]);
}
else if(fa!=v)//避免自己的父亲和自己的儿子是同一人
{
low[u]=min(low[u],dfn[v]);
}
}
}
预处理后进行割点判断,用cut[ ]
判断是否为割点
void slove()
{
int son=0,ans=0;
memset(cut,0,sizeof(cut));
dfs(1,0);//以1为根节点
for(int i=2;i<=n;i++)
{
int v=father[i];
if(v==1)//i的父亲是根节点
son++;
if(dfn[v]<=low[i])//满足该条件
cut[v]=1;
}
for(int i=2;i<=n;i++)
{
if(cut[i])
ans++;
}
if(son>1)
ans++;
printf("%d\n",ans);
}
AC代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define maxn 1005
vector<int>vec[maxn];
int low[maxn],dfn[maxn],cut[maxn],father[maxn],times,n;
void init()
{
times=0;
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(father,0,sizeof(father));
memset(vec,0,sizeof(vec));
}
void dfs(int u,int fa)
{
low[u]=dfn[u]=++times;//次序和时间戳
father[u]=fa;
int len=vec[u].size();
for(int i=0;i<len;i++)
{
int v=vec[u][i];
if(!dfn[v])
{
dfs(v,u);//儿子和父亲
low[u]=min(low[u],low[v]);
}
else if(fa!=v)
{
low[u]=min(low[u],dfn[v]);
}
}
}
void slove()
{
int son=0,ans=0;
memset(cut,0,sizeof(cut));
dfs(1,0);
for(int i=2;i<=n;i++)
{
int v=father[i];
if(v==1)//i的父亲是根节点
son++;
if(dfn[v]<=low[i])
cut[v]=1;
}
for(int i=2;i<=n;i++)
{
if(cut[i])
ans++;
}
if(son>1)
ans++;
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d",&n)&&n)
{
int u,v;
init();
while( scanf("%d",&u)&&u)
{
while(getchar()!='\n')
{
scanf("%d",&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
}
slove();
}
}