BZOJ 3438 浅谈DINIC及一点点优化卡时技巧
来源:互联网 发布:java数组删除指定元素 编辑:程序博客网 时间:2024/06/03 17:43
如tarjan一样,学了dinic也已经很久了,但还是一直模模糊糊,会打,能a,但一直不知其原理,这道题的构图方式着实不错,烧脑子,值得记叙。
description:
小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:
只有一行,包括一个整数,表示最大收益
这道题乍一看并不容易想到网络流,但记得某大神说过,不知怎么做的题就往网络流方面想,想着想着,就卡出来了。
突破口是一个种子只能种一块土地,换句话说就必须放弃种在另一块土地的价值,考虑每一种作物,不考虑集合buff,贪心的取较大价值的土地,就是放弃较小的土地,那这两条边并在一起的最大流即最小割必然是价值较小的那一块,那对每一个作物,分别向源点连一条流量为a[i]的边,向汇点连一条流量为b[i]的边,就解决了单个作物的价值问题,因为每一条路上的最大流就是较小边权的权值,总的最大流就是应该减去的边权和。
其实单单是这样根本用不到网络流,贪心就好,主要是还有集合buff的问题。
我们要知道,最大流即最小割就是我们想要放弃的边权和,将图分成互不相连得两部分,而对于任意一个点集,只有当全部的点去A或B时才能享受到集合buff,也就是说,最小割里少减了一个集合buff的值,而点集中的所有点都到A,就等于都放弃B,就是这些点通向B的边全部放弃,即全部取到最大流,全部断开,所以这些点在图中就不能再通过另外任何一条边到达源点或汇点,就是说集合buff的权值必须全部取到,那另一边的集合buff就要断开,即满流。而对于整个点集,从源点通过其前往汇点的路径上,必然是流量较小的方案(边集)满流,就是这条路径的最大流。
分析到这一步,对于集合点的构建方式就豁然明朗了。
每个收益i拆成两个点i1、i2,分别表示全部种在A和全部种在B
每个收益i2向对应种子连一条流量为inf的边(为了不影响决策)
源点S向每个收益i2连一条流量为c2i的边
对应种子向每个收益i1连一条流量为inf的边
每个收益i1向汇点T连一条流量为c1i的边
这样,如果点集各部分连向A的满流,部分连向B的满流,为了最大流,buff点与源点汇点的边必须满流,正好表示断开,舍弃buff的加成。
各种情况都被这张图概括,跑一遍dinic就行了。
但是
关于这个dinic,也不是那么简单,这道题有点卡时,稍不注意就要超时,在这里提供一点点卡时技巧(没有当前弧优化,要看当前弧优化点这里)
首先是不是那么6的,bfs时每次queue动态申请空间会炸,时间耗费太严重,不如提前申请好空间,每次清空。当然直接用数组的写法也是可以的,反正不要动态申请就行了,代码:
bool bfs(){ int h=0,t=1; memset(dis,-1,sizeof(dis)); while(!state.empty()) state.pop(); state.push(S); dis[S]=0; while(!state.empty()) { int u=state.front(); state.pop(); for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(dis[v]==-1&&ed[i].w>0) { dis[v]=dis[u]+1; state.push(v); } } } if(dis[T]==-1) return false; return true;}
在dfs时,也有卡时技巧,代码:
int dfs(int u,int low){ int a=0; if(u==T || low==0) return low; //流量为0说明无法增广,return for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(ed[i].w>0&&dis[v]==dis[u]+1) { int tmp=dfs(v,min(low,ed[i].w)); ed[i].w-=tmp,ed[i^1].w+=tmp; a+=tmp; low-=tmp; if(low==0) return a; //流量为0就没有必要继续了 } } if(low) dis[u]=-1; //提前将u的层次图删去,剪枝以免再次访问 return a;}
完整代码如下:
#include<stdio.h>#include<algorithm>#include<queue>#include<cstring>#define INF 0x3f3f3f3fusing namespace std;struct edge{ int v,w,last;}ed[4100010];int num=1,head[100010],dis[100010],sum=0,a[10010],b[10010];int n,m,S,T,x,y,z,ans=0;queue<int> state;void add(int u,int v,int w){ num++; ed[num].v=v; ed[num].w=w; ed[num].last=head[u]; head[u]=num;}bool bfs(){ int h=0,t=1; memset(dis,-1,sizeof(dis)); while(!state.empty()) state.pop(); state.push(S); dis[S]=0; while(!state.empty()) { int u=state.front(); state.pop(); for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(dis[v]==-1&&ed[i].w>0) { dis[v]=dis[u]+1; state.push(v); } } } if(dis[T]==-1) return false; return true;}int dfs(int u,int low){ int a=0; if(u==T || low==0) return low; for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(ed[i].w>0&&dis[v]==dis[u]+1) { int tmp=dfs(v,min(low,ed[i].w)); ed[i].w-=tmp,ed[i^1].w+=tmp; a+=tmp; low-=tmp; if(low==0) return a; } } if(low) dis[u]=-1; return a;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i]; for(int i=1;i<=n;i++) scanf("%d",&b[i]),sum+=b[i]; scanf("%d",&m); S=0,T=n+2*m+1; for(int i=1;i<=n;i++) { add(S,i,a[i]); add(i,S,0); } for(int i=1;i<=n;i++) { add(i,T,b[i]); add(T,i,0); } for(int i=1;i<=m;i++) { scanf("%d",&z); scanf("%d%d",&x,&y); add(S,n+i*2,x); add(n+i*2,S,0); add(n+i*2-1,T,y); add(T,n+y*2-1,0); sum+=x+y; for(int j=1;j<=z;j++) { scanf("%d",&y); add(n+i*2,y,INF); add(y,n+i*2,0); add(y,n+i*2-1,INF); add(n+i*2-1,y,0); } } while(bfs()) ans+=dfs(S,INF); printf("%d",sum-ans);}
嗯,就是这样
- BZOJ 3438 浅谈DINIC及一点点优化卡时技巧
- dinic 优化模板 BZOJ 3438 小M的作物 (最小割)
- BZOJ 2839 浅谈容斥原理组合计数及欧拉定理优化二维幂指数
- 浅谈MySQL优化索引技巧
- 浅谈MyEclipse优化与技巧
- BZOJ 1066 Dinic
- BZOJ 2006 浅谈数据结构优化贪心思路
- SQL技巧及优化
- BZOJ 2140 浅谈 Tarjan 算法及模板
- 浅谈网站遇到问题时的解决办法及提问技巧
- Dinic+当前弧优化
- dinic当前弧优化
- Dinic+当前弧优化
- 浅谈网站标题关键字优化技巧
- 浅谈邮件营销标题优化技巧
- Bash 技巧一点点
- 一点点Websphere v6优化
- BZOJ 4152 浅谈堆优化的SPFA算法
- Android Studio 图片选择器
- jdbc
- Intellij IDEA快捷键 整理
- idea 将项目上传到 github
- 一个自己写的网页计算器
- BZOJ 3438 浅谈DINIC及一点点优化卡时技巧
- 【APIO2014】Palindromes
- substr 和 substring的区别
- C#学习笔记-ref与out
- HDU 3572 网络流最大流 解题报告
- 6581 Number Triangle
- 史上最简单的手机app教程 基于Corona SDK(6)
- java如何从方法返回多个值
- 1930: 今年的第几天?