Description
背景
小M还是个特么喜欢玩MC的孩纸。。。
描述
小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号),现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植可以获得bi的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益,小M找到了规则中共有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以获得c2i的额外收益,所以,小M很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?
Input
第一行包括一个整数n
第二行包括n个整数,表示ai
第三行包括n个整数,表示bi
第四行包括一个整数m
接下来m行,对于接下来的第i行:第一个整数ki,表示第i个作物组合中共有ki种作物,接下来两个整数c1i,c2i,接下来ki个整数,表示该组合中的作物编号。输出格式
Output
只有一行,包括一个整数,表示最大收益
Sample Input
3
421
232
1
23212
Sample Output
11
样例解释
A耕地种1,2,B耕地种3,收益4+2+3+2=11。
数据范围与约定
对于100%的数据,1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。
样例解释
A耕地种1,2,B耕地种3,收益4+2+3+2=11。
数据范围与约定
对于100%的数据,1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。
题解:
S表示种在耕地A上,T表示种在耕地B上.
对于每组作物新建两个点.分别表示同时选A和同时选B;
对于同时选A.
S向该点连同时选A的收益.
该点向它控制的点连正无穷的边.
这样可以保证它控制的点中只要有一个点选的B就要放弃同时选A的收益.
同时选B同理.
总收益-最小割即可.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 4000
#define M 2000000
#define inf 210000000
using namespace std;
int point[N],next[M<<1],n,m,x,sum,T,cnt(1),a[N],b[N],c1,c2,k;
int gap[N],cur[N],pre[N],dis[N];
bool f;
struct use{
int st,en,v;
}e[M<<1];
void add(int x,int y,int v){
next[++cnt]=point[x];point[x]=cnt;
e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
next[++cnt]=point[y];point[y]=cnt;
e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;
}
int isap(){
int i,mn,ans(0),u(1);
gap[0]=T;
for (i=1;i<=T;i++) cur[i]=point[i];
while (dis[1]<T){
f=false;
for (i=cur[u];i;i=next[i])
if (e[i].v&&dis[e[i].en]+1==dis[u]){cur[u]=i;f=true;break;}
if (f){
pre[u=e[i].en]=i;
if (u==T){
mn=inf;
for (i=T;i!=1;i=e[pre[i]].st) mn=min(mn,e[pre[i]].v);
ans+=mn;
for (i=T;i!=1;i=e[pre[i]].st) e[pre[i]].v-=mn,e[pre[i]^1].v+=mn;
u=1;
}
}
else{
gap[dis[u]]--;if (!gap[dis[u]]) return ans;
for (mn=T,i=point[u];i;i=next[i])
if (e[i].v) mn=min(mn,dis[e[i].en]);
gap[dis[u]=mn+1]++;cur[u]=point[u];
if (u!=1) u=e[pre[u]].st;
}
}
return ans;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
scanf("%d",&m);T=n+m+m+2;
for (int i=1;i<=n;i++){
sum+=a[i];
add(1,i+1,a[i]);
}
for (int i=1;i<=n;i++){
sum+=b[i];
add(i+1,T,b[i]);
}
for (int i=1;i<=m;i++){
scanf("%d%d%d",&k,&c1,&c2);
add(1,(i-1)*2+1+n+1,c1);
add(i*2+n+1,T,c2);
sum+=c1+c2;
for (int j=1;j<=k;j++){
scanf("%d",&x);
add((i-1)*2+1+n+1,x+1,inf);
add(x+1,i*2+n+1,inf);
}
}
cout<<sum-isap();
}