HDU 6126 Give out candies (贼巧妙的最小割)
来源:互联网 发布:查看占用80端口的进程 编辑:程序博客网 时间:2024/06/04 18:48
思路:
最小割模型。
考虑如何转化成最小割模型。
先不考虑k个限制条件。
我们要求的是每个孩子的最大的满足度,而最小割,割的是最小容量的边,所以我们需要负权建边,然而板子跑不了负的容量啊,所以我们对于每条边加上一个足够大的值F(题目中虽然没给
(建图的详细方法:对于第i个人,s连点(i,1),点(i,1)连点(i,2)。。。。点(i,m)连t)
然后考虑增加约束的情况。对于约束 x,y,z,要求第x个孩子拿到的糖数-第y个孩子拿到的糖数 <= z。
如果x=1,y = 2,z = 1,那么如果第一个孩子选了3个糖,那么第二个孩子就要至少选3-1个糖。推广:第x个孩子选了i个糖之后,第y个孩子就一定要至少选 i-z 个糖(z是负数也没关系,超出去的话就连汇点。i-z超出去的话就连源点。)。而这种约束是如何通过最小割模型实现的呢?如下图:
图中的1,2,3,4代表着弧,考虑如果我们要选的点在2上,即割边(这条路上最小容量的边)在2上,那么另一个孩子的割边一定在4上。因为如果在3上的话,我们一定可以从inf这条边的得到额外的流量,使得流量汇聚到4中,使得4中有着割边。而如果我们要选的点1上的话,同理判断,如果1的左边没有inf边,那么证明选1的时候3,4上的点都可以选,即:不存在这个约束条件。
最后来考虑无解的情况,如下图:
注意:1,2,3,4表示的弧变了。当我们选1上的点的时候,下边只能选3上的点。当我们选2上的点的时候,下边只能选4上的点。而如果3上没有点,那么1这段弧上的点就都选不了了。所以无解的情况你应该可以大致猜一下了,判断从源点到汇点是否有大于等于inf的流量,有的话就说明找不到满足条件的两个点使得割最小。(如果按照我这张图,1左边那段弧和3左边那段弧里有可以选的点的话,那么就是有解的,而约束成无解的方法和1,3的一样。最终都是要从起点开始约束到终点,这样才会有inf流量)
#include<iostream>#include<cstdio>#include<queue>#include<cstring>#include<map>#define inf 0x3f3f3f3fLLtypedef long long int lli;using namespace std;const lli maxn = 20000;struct edge{ lli to,v,next;}ed[maxn+2000000];lli d[maxn],cur[maxn],pre[maxn],gap[maxn],q[maxn+2000],cnte,head[maxn];void ae(lli x, lli y, lli v) { ed[cnte].to = y; ed[cnte].v = v; ed[cnte].next = head[x]; head[x] = cnte++; ed[cnte].to = x; ed[cnte].v = 0; ed[cnte].next = head[y]; head[y] = cnte++;}void rbfs (lli s,lli t) { lli fi,se; memset(gap,0,sizeof(gap)); memset(d,-1,sizeof(d)); d[t] = 0; gap[0] = 1; fi = se = 0; q[se++] = t; while (fi != se) { lli u = q[fi++]; for (lli i=head[u];~i;i=ed[i].next) { lli v = ed[i].to; if (~d[v]) continue; d[v] = d[u] + 1; q[se++] = v; gap[d[v]]++; } }}lli isap(lli s,lli t){ memcpy(cur,head,sizeof(head)); rbfs (s,t); lli flow = 0, u = pre[s]=s,i; while(d[t] < t+1) { if(u==t) { lli f = inf,neck; for(i= s;i != t;i = ed[cur[i]].to){ if(f > ed[cur[i]].v){ f = ed[cur[i]].v; neck = i; } } for(i = s;i != t;i = ed[cur[i]].to){ ed[cur[i]].v -= f; ed[cur[i]^1].v += f; } flow += f; u = neck; } for(i = cur[u];~i;i=ed[i].next) if(d[ed[i].to]+1 == d[u] && ed[i].v) break; if(~i) { cur[u] = i; pre[ed[i].to] = u; u = ed[i].to; } else{//否则回退,重新找增广路 if(gap[d[u]] == 0 || 0 == (--gap[d[u]])) break;//GAP间隙优化,如果出现断层,可以知道一定不会再有增广路了 lli mind = t+1; for(i = head[u];~i;i = ed[i].next){ if(ed[i].v && mind > d[ed[i].to]){ cur[u] = i; mind = d[ed[i].to]; } } d[u] = mind + 1; gap[d[u]]++; u = pre[u]; } } return flow;}void ini(){ memset(head,-1,sizeof(head));cnte = 0;}int t,n,m,k,v;int ys(int i,int j){//映射关系 if(j == m+1) return n*m+1; return (i-1)*m+j;}int main(){ scanf("%d",&t); while(t--){ ini(); scanf("%d%d%d",&n,&m,&k); int s = 0,t = n*m+1; for(int i = 1;i <= n;i++){ ae(s,ys(i,1),inf); for(int j = 1;j <= m;j++){ scanf("%d",&v); ae(ys(i,j),ys(i,j+1),3000-v); } } int a,b,c; for(int i = 1;i <= k;i++){ scanf("%d%d%d",&a,&b,&c); for(int j = 1;j <= m;j++){ if(j-c < 1) ae(ys(a,j),s,inf); else if(j-c <= m) ae(ys(a,j),ys(b,j-c),inf); else ae(ys(a,j),t,inf); } } lli ans = isap(s,t); if(ans >= inf){ puts("-1"); } else{ printf("%lld\n",n*3000-ans); } } return 0;}
- HDU 6126 Give out candies (贼巧妙的最小割)
- HDU 6126 Give out candies 最小割
- HDU-6126 Give out candies(最小割)
- HDU 6126 Give out candies(最小割)
- HDU 6126 Give out candies(最小割-Dinic)
- [HDU 6126] Give out candies
- hdu6126 Give out candies(SPFA+Dinic)
- hdu 3987(求割边最小的最小割)
- hdu 3046(最小割)
- hdu 3251(最小割)
- hdu 3452(最小割)
- hdu 4289(最小割)
- HDU 6214 Smallest Minimum Cut (最小割最小割边)(两种算法的分析)
- hdu 3996(最大流最小割的应用)
- hdu 5889 Barricade (最短路的最小割)
- zoj 3475 最小割 巧妙建图
- hdu 6214 割边最少的最小割
- hdu 3987 求割边最少的最小割
- Python3 执行Linux Bash命令
- 数据库(第一范式,第二范式,第三范式)
- Rightware的Kanzi界面很快你的全液晶汽车仪表盘
- Python的序列(2)-元组
- CommonsMultipartFile 文件上传
- HDU 6126 Give out candies (贼巧妙的最小割)
- PAT1060——Are They Equal,利用字符串解题
- 算法竞赛入门经典java版程序ch4 UVa213
- 用Shell写一个SSH的小工具
- 一个初学者的vue2.0练习程序
- leetcode[Shortest Unsorted Continuous Subarray]//待整理多种解法
- Handler———理解和应用
- nefu117 素数个数的位数(素数定理)
- 原型模式