【CF 311E】

来源:互联网 发布:制作网页用什么软件 编辑:程序博客网 时间:2024/06/09 21:55

Description

这里写图片描述

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);}
1 0
原创粉丝点击