【bzoj3438】 小M的做物

http://www.lydsy.com/JudgeOnline/problem.php?id=3438 (題目連接)php

題意

  $n$種做物,每種能夠種在A田也能夠種在B田,兩種種植方法有不一樣的收益。$m$個組合,若是一個組合中的做物種在同一塊田地,那麼能夠得到額外的收益。問最大收益。ios

Solution

  最小割。數組

  源點向做物連邊,容量$a[i]$,做物向匯點連邊,容量$b[i]$。spa

  $m$組點,每組兩個。第一個由源點連向它,再連向組合中的做物;第二個連向匯點,由組合中的做物連過來。blog

細節

  mdzz這數組到底要開多大= =get

代碼

// bzoj3438
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf (1ll<<30)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

const int maxn=5010,maxm=1000010;
int head[maxn],a[maxn],b[maxn],n,m,S,T,cnt=1;
LL ans;
struct edge {int to,next,w;}e[maxm<<1];

void link(int u,int v,int w) {
	e[++cnt]=(edge){v,head[u],w};head[u]=cnt;
	e[++cnt]=(edge){u,head[v],0};head[v]=cnt;
}
namespace Dinic {
	int d[maxn];
	bool bfs() {
		for (int i=S;i<=T;i++) d[i]=-1;
		queue<int> q;q.push(S);d[S]=0;
		while (!q.empty()) {
			int x=q.front();q.pop();
			for (int i=head[x];i;i=e[i].next)
				if (e[i].w && d[e[i].to]<0) d[e[i].to]=d[x]+1,q.push(e[i].to);
		}
		return d[T]>0;
	}
	int dfs(int x,int f) {
		if (x==T || f==0) return f;
		int w,used=0;
		for (int i=head[x];i;i=e[i].next) if (d[e[i].to]==d[x]+1 && e[i].w) {
				w=dfs(e[i].to,min(e[i].w,f-used));
				used+=w;e[i].w-=w;e[i^1].w+=w;
				if (used==f) return used;
			}
		if (!used) d[x]=-1;
		return used;
	}
	LL main() {
		LL flow=0;
		while (bfs()) flow+=dfs(S,inf);
		return flow;
	}
}

int main() {
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]),ans+=a[i];
	for (int i=1;i<=n;i++) scanf("%d",&b[i]),ans+=b[i];
	scanf("%d",&m);
	S=0,T=n+2*m+1;
	for (int i=1;i<=n;i++) link(S,i,a[i]),link(i,T,b[i]);
	for (int k,x,y,t,i=1;i<=m;i++) {
		scanf("%d%d%d",&k,&x,&y);
		ans+=x+y;
		link(S,i+n,x);link(i+n+m,T,y);
		for (int j=1;j<=k;j++) scanf("%d",&t),link(i+n,t,inf),link(t,i+n+m,inf);
	}
	printf("%lld",ans-Dinic::main());
	return 0;
}
相關文章
相關標籤/搜索