poj 1523 求割点和割点属于块的块数

题目链接:poj 1523 

题意描述::略


分析:求割点的算法很明显的是用tarjan算法,当一条边u---v时有low[v]>=dfn[u](表示v不能更新到u更以前的节点)这就直接说明了u点u之前的和u的子树给分开,那么u就为割点,但这里有个问题对于根节点用这个判断是否为割点就会出错,看看这个例子:(1,2) (2,3) (3,1),设根节点为1,那么从1开始更新对于节点1的dfn[1]=1,low[1]=1,假设这时先搜到2(注意求割点的时候无向图可以反向更新)则有dfn[2]=2,low[2]=2;因为low[2]>dfn[1]所以low[2]=1,现在搜索到节点3,那么dfn[3]=3,low[3]=2,更新之后返回,因为dfn[2]>low[3],所以2不是割点,返回到节点2,因为low[2]>=dfn[1]=2,所以节点1为割点,显然该图中是没有割点的,所以这样的求法对根节点是不对的,那么只要特殊处理根节点就好,如果根节点的子树的个数超过1则能够说明根节点为割点(注意这里的子树是 这样形成的:从根节点进行搜索,每次沿着以个分支搜索,若为节点没有被搜索完,那么可以继续搜索,分支数将会增加);这里的每个割点属于的块数是如何求的呢? 这里我们直接设一个标记数组来记录割点的块数,当存在满足割点条件的点时,我们就将对应的数组增1,那么这样数组里面存放的数字就是(块数-1)(因为从根节点方向来的那一块不会将割点判断为割点,所以记录块的个数,比总块的个数少1),这个结论对根节点同样适用,求无向图的割点时是否有重边对求割点是没有影响的



贴代码先:


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int N = 1005;
bool g[N][N];
int n, m;
int dfn[N],low[N],index,son,num[N];
int Min(int a, int b)
{
	return a>b?b:a;
}
void Cutvedex(int u)
{
	dfn[u]=low[u]=index++;
	for(int v=n;v<=m;v++)
	{
		if(u==v)continue;
		if(g[u][v])
		{
		if(dfn[v]==-1)
		{
			if(u==n)
				son++;
			Cutvedex(v);
			low[u]=Min(low[u],low[v]);
			if((u!=n&&low[v]>=dfn[u])||(u==n&&son>1))
				num[u]++;
		}
		else low[u]=Min(low[u],dfn[v]);
		}
	}
}
			

int main ()
{
	int k=1;
	int x,y,i;
	bool tag;
	while(scanf("%d",&x)!=EOF)
	{
		if(x==0)
			break;
		tag=false;
		memset(g,0,sizeof(g));
		m=-1,n=1005;
		while(1)
		{
		if(tag)
		  scanf("%d",&x);
		tag=true;
		if(x==0)break;
		scanf("%d",&y);
		g[x][y]=1;
		g[y][x]=1;
		if(m<x)m=x;
		if(m<y)m=y;
		if(n>x)n=x;
		if(n>y)n=y;
		}

	printf("Network #%d\n",k++);
	memset(num,0,sizeof(num));
	memset(dfn,-1,sizeof(dfn));
	memset(low,0,sizeof(low));
	index=1;son=0;
    Cutvedex(n);
	tag=false;
	for(i=n;i<=m;i++)
		if(num[i])
		{
			tag=true;
			printf("  SPF node %d leaves %d subnets\n",i,num[i]+1);
		}
	if(!tag)printf("  No SPF nodes\n");
	printf("\n");
	}
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值