求割边数量的算法

//求割边算法
//给各个点赋值初始深度
//一点前出现的都是这点的祖先,一点后出现的都是这点的子孙
//从起点开始遍历,往孩子递归,
//如果到了没有遍历过(也就是深度为初始化的0),递归遍历该点,并赋值深度,看孩子能否能连到父亲的前面的路径,有则给孩子改变孩子的最小深度,即连到的已遍历过的深度最小点的深度。再判断该点的最小深度是否大于父亲的深度,如果大于则说该父亲节点和孩子点组成的边是割边。
//到了遍历过的点,说明是到了之前已经走过的路径,这用于求最小深度。
#include<stdio.h>
#include<string.h>
int map[500][500]; //边
int ans; //割边数量
int num; //可以连通的点的个数
int adjN,edgeN; //点个数,边个数
int low[500]; //点的最小深度
int depth[500]; //点的深度
int mark[500]; //遍历过做标志
void junge(int now,int par)
//判断图是否连通
{
for(int i=1;i<=adjN;i++)
{
if(map[now][i]==1&&i!=par&&mark[i]!=1)
{
mark[i]=1;
num++;
junge(i,now);
}
}
}
void cutline(int now,int par,int dep)
//求割边数
{
depth[now]=dep;
low[now]=dep;
for(int i=1;i<=adjN;i++)
{
if(par!=i&&map[now][i]==1)
{
if(depth[i]==0)
{
cutline(i,now,dep+1);
if(low[i]<low[now])
{
low[now]=low[i];
}
if(low[i]>depth[now])
{
ans++;
}
}
else if(depth[i]<low[now])
low[now]=depth[i];
}
}
}
int main()
{
freopen("input.txt","r",stdin);
while(scanf("%d %d ",&adjN,&edgeN)==2)
{
int m,n;
ans=0;
num=1;
memset(depth,0,sizeof(depth));
memset(low,0,sizeof(low));
memset(mark,0,sizeof(mark));
memset(map,0,sizeof(map));
for(int i=1;i<=edgeN;i++)
{
scanf("%d %d ",&m,&n);
map[m][n]=1;
map[n][m]=1;
}
mark[1]=1;
junge(1,-1);
if(num==adjN)
{
cutline(1,0,1);
printf("%d\n",ans);
}
else
printf("%d\n",-1);
}
return 0;
$}

posted @ 2011-09-30 00:21  jim_wu  阅读(464)  评论(0编辑  收藏  举报