【bzoj 1934】[Shoi2007]Vote 善意的投票 最小割

236 篇文章 0 订阅
17 篇文章 0 订阅

额,我的是有多久没写网络流了 。。。。手生了

以前对于最小割的理解局限于最大流的演变上,我觉得这道题是一个很好的例子。我们将同意的和s连边,边权为一,将不同意的和t连边边权为1,朋友之间连边,边权还是一,这样一来,点与点之间就建立了联系,比如现在我要让一个原本统一的人不同意,在我们建立的图上面就相当于划掉他和他原来的点之间的连线,而割掉这一条边以后对于答案的贡献就是1,或者说让一个朋友和另外一个朋友产生矛盾,也只需要划去两个朋友之间的连线,同样的,当我们找到一条最小割以后将图 分成了s和t集合而这两个集合之间一定不会有任意两个人之间产生矛盾。因此,问题转变成了最小割问题

本人觉得因该是对于最小割更为本质的应用吧

#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 310
using namespace std;
int n,s,t,head[maxn],tot,m,d[maxn],last[maxn],vd[maxn];
struct edge{
	int v,w,next;
}e[maxn*maxn*2];
void adde(int a,int b,int c){e[tot].v=b,e[tot].w=c,e[tot].next=head[a];head[a]=tot++;}

int dfs(int u,int flow){
	if(u==t)return flow;
	int res=0,temp=0;
	for(int i=last[u];i!=-1;i=e[i].next )if(d[u]==d[e[i].v]+1&&e[i].w>0){
		last[u]=i;
		temp=dfs(e[i].v,min(e[i].w,flow-res));//我擦 一开始写成了flow-e[i].w找了好久 
		res+=temp,e[i].w-=temp,e[i^1].w+=temp;
		if(res==flow)return res;
	}
	if(d[s]>=t)return res;
	vd[d[u]]--;if(vd[d[u]]==0)d[s]=t;
	d[u]++;vd[d[u]]++;
	last[u]=head[u];
	return res;
}

void sap(){
	int ans=0;
	for(int i=0;i<=t;i++)last[i]=head[i];
	while(d[s]<t){
		ans+=dfs(s,1e9);	
	}
	printf("%d",ans);
}

int main(){
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	s=0,t=n+1;
	for(int x,i=1;i<=n;i++){
		scanf("%d",&x);
		x ? (adde(s,i,1),adde(i,s,0)) : (adde(i,t,1),adde(t,i,0));
	}
	
	for(int a,b,i=1;i<=m;i++){
		scanf("%d%d",&a,&b);
		adde(a,b,1),adde(b,a,0);
		adde(b,a,1),adde(a,b,0);
	}
	sap();
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值