●BZOJ 1934 [Shoi2007]Vote 善意的投票

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=1934

题解:

题目有点迷。

S向为1的点连边,为0的点向T连边,
在有关系的两个点之间连双向边。
以上边的容量都为1。
然后求最小割,最小割==最大流,dinic实现。
代码:

#include<queue> 
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 350
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
	int to[MAXN*MAXN*2],cap[MAXN*MAXN*2],nxt[MAXN*MAXN*2],head[MAXN],ent;
	void Init(){
		ent=2; memset(head,0,sizeof(head));
	}
	void Adde(int u,int v,int w){
		to[ent]=v; cap[ent]=w; 
		nxt[ent]=head[u]; head[u]=ent++;
		to[ent]=u; cap[ent]=0; 
		nxt[ent]=head[v]; head[v]=ent++;
	}
	int Next(bool type,int i){
		return type?head[i]:nxt[i];
	}
}E;
int N,M,T,S;
int d[MAXN],cur[MAXN];
bool bfs(){
	memset(d,0,sizeof(d));
	queue<int>q; q.push(S); d[S]=1;
	while(!q.empty()){
		int u=q.front(); q.pop();
		for(int i=E.Next(1,u);i;i=E.Next(0,i)){
			int v=E.to[i];
			if(d[v]||!E.cap[i]) continue;
			d[v]=d[u]+1; q.push(v);
		}
	}
	return d[T];
}
int dfs(int u,int reflow){
	if(!reflow||u==T) return reflow;
	int flowout=0,f;
	for(int &i=cur[u];i;i=E.Next(0,i)){
		int v=E.to[i];
		if(d[v]!=d[u]+1) continue;
		f=dfs(v,min(reflow,E.cap[i]));
		reflow-=f; E.cap[i]-=f;
		flowout+=f; E.cap[i^1]+=f;
		if(!reflow) break;
	}
	if(!flowout) d[u]=0;
	return flowout;
}
int Dinic(){
	int flow=0;
	while(bfs()){
		memcpy(cur,E.head,sizeof(E.head));
		flow+=dfs(S,INF);
	}
	return flow;
}
int main()
{
	scanf("%d%d",&N,&M); S=N+1,T=N+2;
	E.Init();
	for(int i=1,x;i<=N;i++){
		scanf("%d",&x);
		if(x==1) E.Adde(S,i,1);
		else E.Adde(i,T,1);
	}
	for(int i=1,a,b;i<=M;i++){
		scanf("%d%d",&a,&b);
		E.Adde(a,b,1);
		E.Adde(b,a,1);
	}
	int ans=Dinic();
	printf("%d",ans);
	return 0;
}

posted @ 2017-11-30 20:12  *ZJ  阅读(106)  评论(0编辑  收藏  举报