您的位置:首页 > 其它

bzoj3438 小M的作物

2015-10-05 00:40 288 查看

3438: 小M的作物

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 509  Solved: 242

[Submit][Status][Discuss]

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的作物。对于一个点,从源点到该点连一条容量为ai的边,再从该点到汇点连一条容量为bi的边。对于每一个组合,建立两个附加点xj和yj,从源点到xj连一条容量为c1j的边,再从xj到方案中每个点连一条容量为inf的边;从方案中每个点到yj连一条容量为inf的边,再从yj到汇点连一条容量为c2j的边。

在构建的图中用最大流算法求出最小割,再用总收益减去最小割即为满足条件的最大收益。

P.S. 在dfs中记得加流量等于零,将这个点的dis赋值为-1,剪枝。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
#define MAXN 4020000
#define INF 2000000000
using namespace std;
struct edge_type
{
int to,next,w;
}e[MAXN];
int ans,min_cut,n,m,k,s,t,cnt=1,c1,c2;
int a[1005],b[1005],head[3050],p[1005],dis[3050];
void add_edge(int x,int y,int z)
{
e[++cnt]=(edge_type){y,head[x],z};
head[x]=cnt;
e[++cnt]=(edge_type){x,head[y],0};
head[y]=cnt;
}
queue<int>q;
bool bfs()
{
memset(dis,-1,sizeof(dis));
dis[s]=0;
while(!q.empty())q.pop();
q.push(s);
while(!q.empty())
{
int tmp=q.front();
q.pop();
if (tmp==t) return true;
for(int i=head[tmp];i;i=e[i].next) if (dis[e[i].to]<0&&e[i].w)
{
dis[e[i].to]=dis[tmp]+1;
q.push(e[i].to);
}
}
return false;
}
int dfs(int x,int mf)
{
int ret=0,delt;
if (x==t) return mf;
for(int i=head[x];i;i=e[i].next)
if (e[i].w&&dis[e[i].to]==dis[x]+1)
{
delt=dfs(e[i].to,min(e[i].w,mf));
e[i].w-=delt;
e[i^1].w+=delt;
ret+=delt;
mf-=delt;
if (mf==0) return ret;
}
if (ret==0) dis[x]=-1;
return ret;
}
void dinic()
{
min_cut=0;
while (bfs()) min_cut+=dfs(s,INF);
}
int main()
{
ans=0;
memset(head,0,sizeof(head));
scanf("%d",&n);
s=0;
t=n+1;
F(i,1,n) scanf("%d",&a[i]);
F(i,1,n) scanf("%d",&b[i]);
F(i,1,n)
{
ans+=(a[i]+b[i]);
add_edge(s,i,a[i]);
add_edge(i,t,b[i]);
}
n++;
scanf("%d",&m);
F(j,1,m)
{
scanf("%d",&k);
scanf("%d%d",&c1,&c2);
F(i,1,k) scanf("%d",&p[i]);
ans+=(c1+c2);
n+=2;
add_edge(s,n-1,c1);
add_edge(n,t,c2);
F(i,1,k)
{
add_edge(n-1,p[i],INF);
add_edge(p[i],n,INF);
}
}
dinic();
ans-=min_cut;
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: