【USACO5.4.5】奶牛的电信(BSOI2155)

【USACO5.4.5】奶牛的电信


Description

  农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流。这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,...,a(c),且a1与a2相连,a2与a3相连,等等,那么电脑a1和a(c)就可以互发电邮。 

  很不幸,有时候奶牛会不小心踩到电脑上,农夫约翰的车也可能碾过电脑,这台倒霉的电脑就会坏掉。这意味着这台电脑不能再发送电邮了,于是与这台电脑相关的连接也就不可用了。 

  有两头奶牛就想:如果我们两个不能互发电邮,至少需要坏掉多少台电脑呢?请编写一个程序为她们计算这个最小值和与之对应的坏掉的电脑集合。 

  以如下网络为例: 

1*

3 - 2*

  这张图画的是有2条连接的3台电脑。我们想要在电脑1和2之间传送信息。电脑1与3、2与3直接连通。如果电脑3坏了,电脑1与2便不能互发信息了。 

Input

  第一行 四个由空格分隔的整数:N,M,c1,c2.N是电脑总数(1<=N<=100),电脑由1到N编号。M是电脑之间连接的总数(1<=M<=600)。最后的两个整数c1和c2是上述两头奶牛使用的电脑编号。连接没有重复且均为双向的(即如果c1与c2相连,那么c2与c1也相连)。两台电脑之间至多有一条连接。电脑c1和c2不会直接相连。 
  第2到M+1行 接下来的M行中,每行包含两台直接相连的电脑的编号。

Output

  输出共有两行。第一行是使电脑c1和c2不能互相通信需要坏掉的电脑数目的最小值。第二行是排好序的坏掉的电脑的编号列表。注意c1和c2都不能坏掉。如果有多种可能情况,输出第一个数最小的一种,如果第一个数相同,则输出第二个数最小的一种,依此类推。 

Sample Input

3 2 1 21 32 3

Sample Output

13

Solution

非常类似于

【Baltic2008】黑手党(Mafia)(BSOI2891)http://blog.csdn.net/hwzzyr/article/details/56012697

CODE

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
struct Pipe{int next,to,flow,f;}pipe[100005];
Pipe tg[100005],ttg[100005];
int h[1005],cnt=1;
inline void add(int x,int y,int z){
	pipe[++cnt].to=y;pipe[cnt].next=h[x];h[x]=cnt;pipe[cnt].flow=z;pipe[cnt].f=1;
	pipe[++cnt].to=x;pipe[cnt].next=h[y];h[y]=cnt;pipe[cnt].flow=0;pipe[cnt].f=1;
	return ;
}
inline int read(){
	char c;int rec=0;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
	return rec;
}
int N,M,st,ed,n;
int ans,sum;
int Gap[505],dis[505];
inline int SAP(int v,int maxflow){
	if(v==ed)return maxflow;
	int temp=maxflow,i,j,p;
	for(i=h[v];i;i=pipe[i].next){
		if(pipe[i].f==0)continue;
		j=pipe[i].to;
		if(pipe[i].flow&&dis[v]==dis[j]+1){
			p=SAP(j,min(pipe[i].flow,temp));
			temp-=p;pipe[i].flow-=p;pipe[i^1].flow+=p;
			if(temp==0||dis[st]==n)return maxflow-temp;
		}
	}
	if(--Gap[dis[v]]==0)dis[st]=n;
	else Gap[++dis[v]]++;
	return maxflow-temp;
}
inline void Get(){
	memset(Gap,0,sizeof(Gap));
	memset(dis,0,sizeof(dis));
	Gap[0]=n;sum=0;
	while(dis[st]<n)sum+=SAP(st,inf);
	return ;
}
inline void Solve(){
	ans=sum;
	cout<<ans<<endl;
	int i,j;
	for(i=1;i<=N;i++){
		if(i!=st-N&&i!=ed&&pipe[i*2].f==1){
			for(j=1;j<=cnt;j++)tg[j]=pipe[j];
			for(j=1;j<=cnt;j++)pipe[j]=ttg[j];
			pipe[i*2].f=pipe[i*2+1].f=0;
			Get();
			if(ans>sum){
				cout<<i<<" ";
				ttg[i*2].f=ttg[i*2+1].f=0;
				ans=sum;
			}
			else for(j=1;j<=cnt;j++)pipe[j]=tg[j];
		}
	}
	return ;
}
int main(){
	N=read();M=read();st=read();ed=read();
	int i,x,y;
	for(i=1;i<=N;i++)add(i,i+N,1);
	for(i=1;i<=M;i++){
		x=read();y=read();
		add(x+N,y,inf);add(y+N,x,inf);
	}
	st=st+N;n=N*2;
	for(i=1;i<=cnt;i++)ttg[i]=pipe[i];
	Get();
	Solve();
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值