poj1523 SPF

链接:http://poj.org/problem?id=1523

题意:有一个计算机网络,如果去掉其中某一台计算机后,整个网络不能相互连通,

问这样的计算机有几台。并且求出若去掉这样一台计算机后,整个网络变成几个连通分量。


解析:求图的割点,并求删除此割点后,图变成几个连通分量。

用tarjan算法求图的割点。

割点有两种情况:

1.割点为树根。如果树根有大于1个的孩子,则该树根为割点。删除该割点,连通分量=孩子个数;

2.割点为普通节点。如果一个普通节点(非根节点)满足dfn[u]<=low[v](edge(u,v)),

则该节点为割点。删除该节点,连通分量=满足该条件的子节点(v为u的子节点)的个数+1。


#include<cstdio>
#include<cstring>
#define MAXN 1005
using namespace std;

struct Edge
{
   int to;
   int next;
}edge[MAXN*4];
struct Cut
{
  int is;
  int ans;
}cut[MAXN];
int head[MAXN],dfn[MAXN],low[MAXN];
int ecnt,index,root=1;//设置dfs树的根节点为1
void add(int u,int v)//无向图,双向边
{
	edge[ecnt].to=v;
	edge[ecnt].next=head[u];
	head[u]=ecnt++;
	
	edge[ecnt].to=u;
	edge[ecnt].next=head[v];
	head[v]=ecnt++;
}

void tarjan(int u,int fa)
{
	int i,v,cnt=0;     //cnt记录节点的孩子个数
	dfn[u]=low[u]=++index;
    for(i=head[u];i!=-1;i=edge[i].next)
	{
		v=edge[i].to;
	     if(v==fa)   //不能再回去访问父节点
			 continue;
		 if(!dfn[v])
		 {
		    tarjan(v,u);
			cnt++;
			if(low[u]>low[v])
				low[u]=low[v];
			if(root==u&&cnt>1)//根为割点的情况
			{
			   cut[u].is=1;
			  cut[u].ans=cnt-1;//这里cnt减去1,是为了符合最后的输出,因为最后的输出加了1
			}
			if(root!=u&&dfn[u]<=low[v])
			{
			    cut[u].is=1;
				cut[u].ans++; //连通分量=满足该条件的子节点(v为u的子节点)的个数+1,这里加1放在了最后的输出
			}
		 }
		 else if(low[u]>dfn[v])
			 low[u]=dfn[v];
	}
}


int main()
{
	int a,b,sig,num=1,max,i;
	while(scanf("%d",&a),a)
	{
		scanf("%d",&b);
		ecnt=0;
		max=0;
		memset(head,-1,sizeof(head));
		 if(a>max)
			 max=a;
		 if(b>max)
			 max=b;
		add(a,b);
		
	   while(scanf("%d",&a),a)
	   {
	        scanf("%d",&b);
			if(a>max)
			 max=a;
		    if(b>max)
			 max=b;
			add(a,b);
	   }
	   memset(cut,0,sizeof(cut));
		memset(dfn,0,sizeof(dfn));
		index=0;
		sig=0;
		tarjan(1,-1);//初始化根节点的父节点为-1,也就是没有父节点
		printf("Network #%d\n",num++);
		for(i=1;i<=max;i++)
			if(cut[i].is)
			{
			    printf("  SPF node %d leaves %d subnets\n",i,cut[i].ans+1);
				sig=1;
			}
		if(!sig)
		   printf("  No SPF nodes\n");
		printf("\n");
	}
   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值