您的位置:首页 > 其它

【bzoj3438】【小M的作物】【最小割】

2016-04-17 16:05 429 查看

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。

题解:

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
,next[M<<1],n,m,x,sum,T,cnt(1),a
,b
,c1,c2,k;
int gap
,cur
,pre
,dis
;
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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: