【bzoj3438】【小M的作物】【最小割】
2016-04-17 16:05
489 查看
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上.
对于每组作物新建两个点.分别表示同时选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(); }
相关文章推荐
- 機器學習基石(Machine Learning Foundations) 机器学习基石 作业四 课后习题解答
- 线程的同步与互斥
- Android Tween动画之RotateAnimation实现图片不停旋转
- linux 线程创建 同步与互斥
- Cannot create JDBC driver of class '' for connect URL 'jdbc:mysql://localhost:3306/test'
- 【matlab】:matlab如何实现计算三个点组成的角的角度值
- c语言 字符串的拼接和分割
- activiti 数据库连接配置
- activiti 数据库连接配置
- 求导的经典讲解
- iOS开发数据库篇—SQL
- HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
- Android开发性能优化总结(一)
- Proxy-Stub模式分析(草稿)
- 堆+++
- 第五周项目一(5)-三角形类的雏形
- 数据结构之线性结构(stack、queue、linklist)概念
- 假设知道所有的音乐文件都在XXX盘中,请从根目录开始搜索出所有的音乐文件
- 矩阵快速幂模板(可以在二重循环或者三重循环的地方取模)
- IT人该如何向自动化综合人才转变