BZOJ4177Mike的农场——最小割
题目描述
Mike有一个农场,这个农场n个牲畜围栏,现在他想在每个牲畜围栏中养一只动物,每只动物可以是牛或羊,并且每个牲畜围栏中的饲养条件都不同,其中第i个牲畜围栏中的动物长大后,每只牛可以卖a[i]元,每只羊可以卖b[i]元,为了防止牛羊之间相互影响,Mike找到了m条规律,每条规律给出一个三元组(i, j, k)表示如果第i个围栏和第j个围栏养的是不同的动物,那么Mike就需要花费k的代价请人帮忙处理牛羊之间的影响。不过同时Mike也发现k条特殊的规则(S, a, b),表示如果S中所有牲畜围栏中都养的是动物a,那么Mike可以获得b的额外收入。现在Mike想知道他该在哪些围栏中饲养什么动物才能使得总收益最大,为了简化问题,你只需要输出最大收益。
输入
第一行三个整数n、m、k,表示一共有n个围栏,m条规律,k条规则。
第二行有n个整数,表示a[i]。
第三行有n个整数,表示b[i]。
接下来m行,每行有三个整数(i, j, k)表示一条规则。
再接下来k行,每行一开始有三个整数t、a和b,表示一条规则(S, a, b),其中S的大小为t,接下来
t个整数表示S中的元素(a为0表示全为牛,a为1表示全为羊)。
输出
输出一个整数ans,表示最大收益。
样例输入
1 2 3 1
2 3 1 2
1 2 3
1 3 2
2 0 100 1 2
样例输出
提示
对于100的数据,n <= 5000, m <= 5000, k <= 5000, a = 0 or 1。
我们需要对每个围栏进行决策——选牛还是选羊。那么就将源点看成牛,将汇点看成羊,对于每个围栏分别与源汇点连边,流量为对应选牛或羊的代价。对于每个规则将对应点之间连双向边,流量为对应代价。对于特殊规则,如果是选牛的就新建一个节点与源点连边,流量为对应收益,反之则与汇点连边,然后再将这个点与特殊规则指定集合中的点分别连边,流量为$INF$。最后答案为所有收益之和$-$最小割。
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<vector> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> #define INF 1000000000 using namespace std; int head[40000]; int next[160000]; int to[160000]; int val[160000]; int d[40000]; int q[40000]; int n,m,k; int s,x,y,v; int a[6000]; int b[6000]; int tot=1; int ans; int S,T; void add(int x,int y,int v) { tot++; next[tot]=head[x]; head[x]=tot; to[tot]=y; val[tot]=v; tot++; next[tot]=head[y]; head[y]=tot; to[tot]=x; val[tot]=0; } bool bfs(int S,int T) { int r=0; int l=0; memset(q,0,sizeof(q)); memset(d,-1,sizeof(d)); q[r++]=S; d[S]=0; while(l<r) { int now=q[l]; for(int i=head[now];i;i=next[i]) { if(d[to[i]]==-1&&val[i]!=0) { d[to[i]]=d[now]+1; q[r++]=to[i]; } } l++; } return d[T]!=-1; } int dfs(int x,int flow) { if(x==T) { return flow; } int now_flow; int used=0; for(int i=head[x];i;i=next[i]) { if(d[to[i]]==d[x]+1&&val[i]!=0) { now_flow=dfs(to[i],min(flow-used,val[i])); val[i]-=now_flow; val[i^1]+=now_flow; used+=now_flow; if(now_flow==flow) { return flow; } } } if(used==0) { d[x]=-1; } return used; } void dinic() { while(bfs(S,T)==true) { ans-=dfs(S,0x3f3f3f); } } int main() { scanf("%d%d%d",&n,&m,&k); S=n+k+1; T=S+1; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); add(S,i,a[i]); ans+=a[i]; } for(int i=1;i<=n;i++) { scanf("%d",&b[i]); add(i,T,b[i]); ans+=b[i]; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&v); add(x,y,v); add(y,x,v); } for(int i=1;i<=k;i++) { scanf("%d%d%d",&s,&y,&v); ans+=v; if(!y) { add(S,n+i,v); } else { add(n+i,T,v); } for(int j=1;j<=s;j++) { scanf("%d",&x); if(!y) { add(n+i,x,INF); } else { add(x,n+i,INF); } } } dinic(); printf("%d",ans); }