Description

【CF 311E】_dinic

Solution

网络流

一看就知道是网络流。

最小割

往网络流的方向去想,答案=所有的赞助-不要的赞助-喝茶的费用-牛变性的费用。
让不要的东西最小,就是经典的最小割模型。

连边

因为有牛还有人,所以要建立牛的点,还要建立人的点。
根据上面的想法,我们先解决牛的变性问题:
如果一头牛是雄性的,那么我们把S向i连一大小为变性的费用(bian[i])的边,如果割掉了这条边表示我让这头牛变性。雌性的话类似。
现在考虑,人的限制问题:很显然一个人要雄性的把S向i+n连一条大小为赞助费+(茶费)(v[i]+(g)),但是要让所有的牛都满足情况怎么办?
比如说我这个人要求这些牛是雄性,那么就是要求那些是雌性的牛与T的边割掉(变性),为了使这些人代表的点对边的连通具有影响性,那么这个人向所有牛连一条长度为无穷大的边(不会被割掉),这样的话,在没有割掉这个人的赞助的情况下需要把所有雌性的牛的变性费用(割边)加上才会断开连通。如果这个人要雌性,就用那些牛向这个人连边。
dinic正常切过。

Code

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=500007;
int i,j,k,l,t,n,m,ans,g,xing[maxn],bian[maxn],se,len,you;
int last[maxn*2],next[maxn*2],first[maxn*2],chang[maxn*2],fan[maxn*2],num;
int S,T;
int data[maxn],d[maxn];
void add(int x,int y,int z){
last[++num]=y;
next[num]=first[x];
first[x]=num;
chang[num]=z;
fan[num]=num+1;
last[++num]=x;
next[num]=first[y];
first[y]=num;
chang[num]=0;
fan[num]=num-1;
}
bool bfs(){
memset(d,0,sizeof(d));
int head=0,tail=1,i,j,now;
data[head]=S,d[S]=1;
while(head<tail){
now=data[++head];
rep(i,now){
if(chang[i]&&!d[last[i]]){
data[++tail]=last[i];
d[last[i]]=d[now]+1;
}
}
}
return d[T]!=0;
}
int dinic(int x,int y){
int i,j,k=0;
if(x==T)return y;
rep(i,x){
if(chang[i]&&d[last[i]]==d[x]+1){
j=dinic(last[i],min(y,chang[i]));
if(j){
chang[i]-=j;
chang[fan[i]]+=j;
k+=j;
y-=j;
if(y<=0)break;
}
}
}
if(y<=0)d[x]=-1;
return k;
}
int main(){
scanf("%d%d%d",&n,&m,&g);
S=0,T=n+m+1;
fo(i,1,n)scanf("%d",&xing[i]);
fo(i,1,n){
scanf("%d",&bian[i]);
if(xing[i])add(i,T,bian[i]);
else add(S,i,bian[i]);
}
fo(i,1,m){
scanf("%d%d%d",&se,&l,&len);ans+=l;
fo(j,1,len){
scanf("%d",&k);
if(se)add(k,i+n,0x7fffffff);
else add(i+n,k,0x7fffffff);
}
scanf("%d",&you);
if(se)add(i+n,T,l+you*g);else add(S,i+n,l+you*g);
}
while(bfs())ans-=dinic(S,0x7fffffff);
printf("%d\n",ans);
}