BZOJ 2768 [JLOI2010]冠军调查

题解:

       一道挺水的最小割,然而并不会做。

       建立超级源汇点,希望切尔西赢的从S向它连容量为1的边,希望切尔西输的从它向T连容量为1的边。在朋友之间连一条双向边,答案就是最小割。

       如果存在一条从S到T的路径,相当于产生了冲突。必须说谎(割掉到S或T的边)或者与朋友意见不统一(割掉和朋友的边)

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<time.h>
#include<vector>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
const double eps=1e-8;
const int inf=0x3f3f3f3f;

int n,m,E,S,T,a[N];
int fir[N],nex[N<<1],arr[N<<1],cap[N<<1],len[N<<1],cur[N<<1],dis[N];
queue<int> q;

namespace FastIO {
	template<typename tp> inline void read(tp &x) {
		x=0; register char c=getchar(); register bool f=0;
		for(;c<'0'||c>'9';f|=(c=='-'),c = getchar());
		for(;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0',c = getchar());
		if(f) x=-x;
	}
	template<typename tp> inline void write(tp x) {
		if (x==0) return (void) (putchar('0'));
		if (x<0) putchar('-'),x=-x;
		int pr[20]; register int cnt=0;
		for (;x;x/=10) pr[++cnt]=x%10;
		while (cnt) putchar(pr[cnt--]+'0');
	}
	template<typename tp> inline void writeln(tp x) {
		write(x);
		putchar('\n');
	}
}
using namespace FastIO;

void Add_Edge(int x,int y,int c) {
	nex[++E]=fir[x];
	cap[E]=c;
	fir[x]=E; arr[E]=y;
	nex[++E]=fir[y];
	cap[E]=0;
	fir[y]=E; arr[E]=x;
}

void Init() {
	read(n); read(m); E=1;
	S=0,T=n+1;
	for (int i=1;i<=n;i++) read(a[i]);
	for (int i=1;i<=n;i++) {
		if (a[i]) Add_Edge(S,i,1);
		else Add_Edge(i,T,1);
	}
	for (int i=1;i<=m;i++) {
		int x,y; read(x); read(y);
		Add_Edge(x,y,1);
		Add_Edge(y,x,1);
	}
}

int bfs() {
	memset(dis,0x3f,sizeof(dis));
	dis[S]=0; q.push(S);
	while (!q.empty()) {
		int u=q.front(); q.pop();
		for (int i=fir[u];i;i=nex[i]) {
			int v=arr[i];
			if (dis[v]<inf||!cap[i]) continue;
			dis[v]=dis[u]+1;
			q.push(v);
		}
	}
	return dis[T]<inf;
}

int dfs(int x,int maxflow) {
	if (x==T||!maxflow) return maxflow;
	int ans=0;
	for (int i=cur[x];i;cur[x]=i=nex[i]) {
		int v=arr[i];
		if (dis[v]==dis[x]+1&&cap[i]) {
			int del=dfs(v,min(maxflow,cap[i]));
			ans+=del; maxflow-=del;
			cap[i]-=del; cap[i^1]+=del;
		}
	}
	return ans;
}

int main() {
	Init();
	int flow=0;
	while (bfs()) {
		for (register int i=0;i<=n+1;i++) cur[i]=fir[i];
		flow+=dfs(S,inf);
	}
	printf("%d",flow);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值