题面: 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\n",ans-res);
return 0;
}