bzoj3438 小M的作物
2015-10-05 00:40
288 查看
3438: 小M的作物
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 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
3421
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); }
相关文章推荐
- 我与软件工程
- 菜鸟的Linux历程-LAMP搭建之环境准备
- Install openCV in Linux
- 《TCP/IP详解 卷一:协议》读书笔记--Ping程序
- RAC-DG升级后无法同步应用案例一则
- Kinect2.0+OpenCV获取骨骼图
- Codeforces Round #323 (Div. 1) B. Once Again... (最长不下降序列_DP)
- Using OpenCV with Eclipse (plugin CDT)
- 使用Mac开发Android/iOS/OS X图标生成工具推荐
- 二叉树的三种遍历
- cinder glusterfs driver代码结构
- appium初次安装(mac)
- 这个家族没有后盾,不狠——影响
- 快速排序
- HDOJ 题目5496 Beauty of Sequence(数学)
- contenteditable
- C/C++ 拾遗
- Mybatis系列(九)Spring & Mybatis整合
- ocp-100
- BestCoder Round #48 ($)HDU5284 wyh2000 and a string problem