题面: 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想知道他该在哪些围栏中饲养什么动物才能使得总收益最大,为了简化问题,你只需要输出最大收益。
思路:最小割。
先把所有的收益加起来,然后建图跑最小割,最小割就是最小损失的收益,总收益-最小损失就是答案
对于每个围栏建一个点,由S向每个点连a[i]的边,由每个点再向T连b[i]的边,最终与S相连,那么它就割掉了连向T的边,表示最终这个围栏养牛,将损失养羊的收益a[i],与T相连同理。
对于规律(i,j,k),就在(i,j)之间连权值为k的双向边,其实就是组合收益的建图
对于规则(S,a,b),就新建一个点,并向S中所有点连inf的边,如果是牛就从源向新点连一条权值为b的边,否则向汇连。
以都选牛有收益为例,当两个点都选了牛,就会割掉羊的边,那么这条新边就不会被割了,我们就得到了b的收益。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> const int maxn=20010,maxm=1000010,maxq=1000000,inf=(int)1e9; using namespace std; int n,m,k,a[maxn],b[maxn],dis[maxn],pre[maxm],now[maxn],son[maxm],val[maxm],tot=1,S=0,T=maxn-1,q[maxq+10],head,tail,ans,res;char ch; void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} void ins(int a,int b,int c){add(a,b,c),add(b,a,0);} void read(int &x){ for (ch=getchar();!isdigit(ch);ch=getchar()); for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; } bool bfs(){ memset(dis,-1,sizeof(dis)); q[1]=S,head=0,tail=1,dis[S]=0; do{ if (++head>maxq) head=1; int x=q[head]; for (int y=now[x];y;y=pre[y]) if (dis[son[y]]==-1&&val[y]){ if (++tail>maxq) tail=1; dis[son[y]]=dis[x]+1,q[tail]=son[y]; } }while (head!=tail); return dis[T]>0; } int find(int x,int low){ int res=0,y; if (x==T) return low; for (y=now[x];y;y=pre[y]){ if (dis[son[y]]!=dis[x]+1||!val[y]) continue; int tmp=find(son[y],min(low,val[y])); val[y]-=tmp,val[y^1]+=tmp,res+=tmp,low-=tmp; if (!low) break; } if (!y) dis[x]=-1; return res; } int main(){ scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=n;i++) read(a[i]),ins(S,i,a[i]),ans+=a[i]; for (int i=1;i<=n;i++) read(b[i]),ins(i,T,b[i]),ans+=b[i]; for (int i=1,x,y,z;i<=m;i++) read(x),read(y),read(z),add(x,y,z),add(y,x,z); for (int i=1,t,x,y;i<=k;i++){ read(t),read(x),read(y),ans+=y; if (!x){ ins(S,++n,y); for (int j=1,z;j<=t;j++) read(z),ins(n,z,inf); } else{ ins(++n,T,y); for (int j=1,z;j<=t;j++) read(z),ins(z,n,inf); } } while (bfs()) res+=find(S,inf); printf("%d ",ans-res); return 0; }