[USACO5.4]奶牛的电信Telecowmunication,洛谷之提高历练地,较复杂图论II

正题

       第五题:[USACO5.4]奶牛的电信Telecowmunication

       这道题做多网络流的人一看就知道是一道最小割点的题目。

       做多强联通的人一看就知道是一道割点(割顶)的题目。

       如果让我们用网络流来做,我们会怎样构图呢?

       根据题目的性质我们可以知道,每个点只能被割一次。所以我们怎么限制这个条件呢?明显就是把一个点拆成两个点,然后在其中直连一条流量为1的边。其他的原图有的边直接连即可(无向当然要建)。最后从保证c1和c2不能被割,于是把c1的出点作为源点,把c2的入点作为汇点,跑一遍最大流来求出最小割点集即可。

代码<强联通不会>

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define INF 1e9
using namespace std;

int n,m,c1,c2;
int begin,end;
struct edge{
	int y,next,c;
}s[100010];
int first[210];
int len=1;
queue<int> f;
int h[110];

void ins(int x,int y,int c){
	len++;s[len].y=y;s[len].c=c;s[len].next=first[x];first[x]=len;
	len++;s[len].y=x;s[len].c=0;s[len].next=first[y];first[y]=len;
}

bool bfs(){
	f.push(begin);
	for(int i=1;i<=2*n;i++)
		h[i]=INF;
	h[begin]=0;
	while(!f.empty()){
		int x=f.front();
		f.pop();
		for(int i=first[x];i!=0;i=s[i].next){
			int y=s[i].y;
			if(h[y]==1e9 && s[i].c>0){
				h[y]=h[x]+1;
				f.push(y);
			}
		}
	}
	return h[end]!=1e9;
}

int dfs(int x,int t){
	if(x==end) return t;
	int tot=0;
	for(int i=first[x];i!=0;i=s[i].next){
		int y=s[i].y;
		if(t==tot) return t;
		if(h[y]==h[x]+1 && s[i].c>0){
			int my=dfs(y,min(s[i].c,t-tot));
			tot+=my;s[i].c-=my;s[i^1].c+=my;
		}
	}
	if(tot==0) h[x]=0;
	return tot;
}

int max_flow(){
	int tot=0;
	while(bfs()){
		int dx=dfs(begin,1e9);
		while(dx!=0){
			tot+=dx;
			dx=dfs(begin,1e9);
		}
	}
	return tot;
}

int main(){
	scanf("%d %d %d %d",&n,&m,&c1,&c2);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d %d",&x,&y);
		ins(x+n,y,INF);
		ins(y+n,x,INF);
	}
	begin=0;end=2*n+1;
	for(int i=1;i<=n;i++)
		ins(i,i+n,1);
	begin=c1+n;
	end=c2;
	printf("%d",max_flow());
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值