#270. 电厂计划

【题目描述】:

停电,漆黑的夜晚。

ACM + +是一家电力公司。该公司拥有数个发电厂,每一个供应一个小面积,这些发电厂给这个公司带来了很多的麻烦,在某些地区没有足够的电力,而在其他地区却有大量的盈余。

ACM ++因此决定将一些发电厂连接成一个网络。当然第一阶段,没有必要将所有的发电厂连接到一个网络,但另一方面,它必须在关键地方建立冗余连接,即网络不保证是连通的。现在提出了各种连接的计划,并已开始复杂的评估。

必须考虑的评估标准之一是创建的网络的可靠性。我们假设可以发生的最坏的事件是一个发电厂故障,这可能会导致网络分成几个部分。虽然每一部分都可以工作,但被分成的部分越多,麻烦可能性就越大。因此,我们必须找出所有方案中,某个电厂故障,会形成的最大块数。

【输入描述】:

输入由若干实例组成。

每个实例第一行都包含两个整数P和C(1 <= P = 10,000,C >= 0),中间用空格隔开。P是电厂的数量。电厂编号为0到P - 1之间的整数。C是边数。下面的C行,每一行包含两个整数0 < = P1,P2<P用一个空格隔开,这意味着电厂P1和P2连接。每个连接不会重复描述。输入终止的行包含两个零。

【输出描述】:

输出由若干行组成。输出的第i行对应于第i个输入实例。输出的每一行由一个整数组成,即通过在实例中删除一个连接点,最多可以使网络分成的最大块数。

【样例输入】:

3 3
0 1
0 2
2 1
4 2
0 1
2 3
3 1
1 0
0 0

【样例输出】:

1
2
2

【时间限制、数据范围及描述】:

时间:1s 空间:64M

1 <= P = 10,000

注意没有边的情况

 算法:Tarjan算法应用--无向图 ,即Tarjan算法求割点、桥、缩点

具体算法蛮难的,,,我是学了好久......以及,在调试的时候,输入输出文件和cpp文件不在一个文件夹,所以,,,调试了一个半小时??!!妖怪吧一群人.........

//本代码借鉴较多,各位大佬不要介意哈~~顺便膜拜一下orz 
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>

using namespace std;

const int N=100005;

int n,m,t,ec;
int p[N];
int dfn[N],low[N]; 
int cut[N];
struct node
{
	int next;
	int u,v;
}edge[N*2];
/*********************** 
       链式前向星 
***********************/

void insert(int u, int v)
{	 
	edge[++ec].u = u; 
	edge[ec].v = v;
	edge[ec].next = p[u];
	p[u] = ec;
	return ;
}
int read()
{
	int ans=0,f=1;
	char c;
	c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')
		f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		ans=ans*10+c-'0';
		c=getchar();
	}
	return ans*f;
}
/***********************
     Tarjan算法应用 
	求无向图的桥及缩点 
***********************/

void tarjan(int u,int fa)
{
	dfn[u]=low[u]=++t;	//时间戳,时间戳计数,祖先时间。 

	for(int i=p[u];i;i=edge[i].next)
	{
		int v=edge[i].v;
		if(v==fa)//如果是【u v】边跳过 

		continue;
		if(!dfn[v])
		{
			tarjan(v,u);
			low[u]=min(low[u],low[v]);//利用子孙,更新能回指的祖先时间戳 

			if(low[v]>=dfn[u])//如果u是割点 

			cut[u]++;//u属于的割点块+1 

		}
		else
	    low[u]=min(low[u],dfn[v]);
	}
	return ;
}
void init()//多组数据时,所有数组和栈清空 

{
	memset(edge,0,sizeof(edge));
	memset(p,0,sizeof(p));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(cut,0,sizeof(cut));
	ec=0;
	t=0;
	return ;
}
int main()
{
	freopen("51.in","r",stdin);
	freopen("51.out","w",stdout);
	int a,b;
	while(1)
	{
	    int c=0;
	    int maxcut=-1;
		n=read();
		m=read();
		if(m==0&&n==0)
		break;
		init();
		for(int i=0;i<m;i++)
		{
			a=read();
			b=read();
			insert(a+1,b+1);
			insert(b+1,a+1);
		}
		for(int i=1;i<=n;i++)
		{
			if(dfn[i]==0)
			{
				c++;
				cut[i]=-1;
				tarjan(i,-1);
			}
		}
		for(int i=1;i<=n;i++)
		maxcut=max(maxcut,cut[i]);
		cout<<c+maxcut<<endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值