1934: [Shoi2007]Vote 善意的投票 (网络流)

1934: [Shoi2007]Vote 善意的投票

如果把每个人都看做一个节点,题意其实就是等价于求把点集划分为2个独立部分的最小代价;
我们把赞成的点都引向汇点一条流量为1的边;
从原点向反对的点都引一条流量为1的边;
每一对好友之间连一条容量为1的边;
那么最小代价就是从源到汇的最小割,而最小割==最大流;

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int Mn = 300 + 10, Me = Mn * Mn * 2;
int hd[Mn],nxt[Me],to[Me],f[Me],cnt;
int step[Mn],que[Mn];
int S,T;
int n,m;
inline void add(int x,int y,int z)
{
	to[cnt] = y;
	f[cnt] = z;
	nxt[cnt] = hd[x];
	hd[x] = cnt++;
	
	to[cnt] = x;
	f[cnt] = 0;
	nxt[cnt] = hd[x];
	hd[x] = cnt++;
}
inline int zeng(int x,int flow)
{
	if(x == T) return flow;
	int res(0);
	for(int i = hd[x];~i && res < flow; i = nxt[i])
	if(f[i] && step[to[i]] == step[x] + 1)
	{
		int dt = zeng(to[i],min(flow - res,f[i]));
		f[i] -= dt,f[1^i] += dt,res += dt;
	}
	if(!res) step[x] = -1;
	return res;
}
inline bool check()
{
	memset(step,-1,sizeof step);
	int h = 1 , t = 2;
	que[1] = S;
	step[S] = 0;
	while(h < t)
	{
		int sta = que[h++];
		for(int i = hd[sta];~i; i = nxt[i])
		if(f[i] && step[to[i]] == -1)
		{
			step[to[i]] = step[sta] + 1;
			que[t++] = to[i];
		}
	}
	return ~step[T];
}
inline int dinic()
{
	int res(0);
	while(check()) res += zeng(S,0x7fffffff);
	return res;
}
int main()
{
	memset(hd,-1,sizeof hd);
	scanf("%d%d",&n,&m);
	S = 0, T = n+1;
	for(int i = 1,x; i <= n; i++)
	{
		scanf("%d",&x);
		if(x) add(S,i,1);
		else add(i,T,1);	
	}
	for(int i = 1,x,y; i <= m; i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y,1);
		add(y,x,1);
	}
	printf("%d\n",dinic());
	return 0;
} 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值