[bzoj1934/2768][Shoi2007]Vote 善意的投票_最小割

Vote 善意的投票 bzoj-1934 Shoi-2007

题目大意题目链接

注释:略。


想法

这是最小割的一个比较基本的模型。

我们将所有当前同意的小朋友连向源点,边权为1。不容易的连向汇点,边权为1。

如果两个小朋友是好朋友那就把他们之间连一条边权为1的无向边即可。

最后和源点联通的点表示选择了同意,和汇点联通的点表示选择不同意。

Code

#include <bits/stdc++.h>
#define inf 1000000000 
#define N 100010 
using namespace std;
int to[N<<3],nxt[N<<3],head[N<<3],tot=1,f[N<<3],dis[N<<3],s,t,n,m;
inline void add(int x,int y,int z)
{
	to[++tot]=y; f[tot]=z; nxt[tot]=head[x]; head[x]=tot;
	to[++tot]=x; f[tot]=0; nxt[tot]=head[y]; head[y]=tot;
}
bool bfs()
{
	queue<int>q; memset(dis,-1,sizeof dis); while(!q.empty()) q.pop();
	q.push(s); dis[s]=0; while(!q.empty())
	{
		int x=q.front(); q.pop(); for(int i=head[x];i;i=nxt[i]) if(f[i]&&dis[to[i]]<0)
		{
			dis[to[i]]=dis[x]+1; q.push(to[i]);
			if(to[i]==t) return true;
		}
	}
	return false;
}
int dinic(int x,int fl)
{
	int tmp=fl;
	if(x==t) return fl;
	for(int i=head[x];i;i=nxt[i]) if(f[i]>0&&dis[to[i]]==dis[x]+1)
	{
		int a=dinic(to[i],min(f[i],tmp));
		if(!a) dis[to[i]]=-1;
		tmp-=a; f[i]-=a; f[i^1]+=a;
		if(!tmp) break;
	}
	return fl-tmp;
}
int main()
{
	scanf("%d%d",&n,&m); s=n+1,t=n+2; for(int i=1;i<=n;i++)
	{
		int x; scanf("%d",&x);
		if(x) add(s,i,1); else add(i,t,1);
	}
	for(int i=1;i<=m;i++)
	{
		int x,y; scanf("%d%d",&x,&y);
		add(x,y,1); add(y,x,1);
	}
	int ans=0; while(bfs()) ans+=dinic(s,inf); cout << ans << endl ;
	return 0;
}

小结:最小割。

posted @ 2019-01-08 15:07  JZYshuraK_彧  阅读(46)  评论(0编辑  收藏