洛谷题目传送门

了解网络流和dinic算法请点这里(感谢SYCstudio)

题目

题目背景

这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你。(奶牛混乱的原因看题目描述)

题目描述

在一个农场里有n块田地。某天下午,有一群牛在田地里吃草,他们分散在农场的诸多田地上,农场由m条无向的路连接,每条路有不同的长度。

突然,天降大雨,奶牛们非常混乱,想要快点去躲雨。已知每个田地都建立有一个牛棚,但是每个牛棚只能容纳一定数量的牛躲雨,如果超过这个数量,那多出的牛只能去别的田地躲雨。奶牛们每移动1的距离花费1时间,奶牛们想知道它们全部都躲进牛棚,最少需要多少时间。(即最后一头奶牛最少要花多久才能躲进牛棚)。

输入输出格式

输入格式:

第一行输入两个整数N,M。N表示田地块数,M表示路径数。

接下来N行,每行两个整数S,P,分别表示该田地现在有几头牛以及该田地的牛棚最多可以容纳多少牛。

接下来M行,每行3个整数A,B,C,表示存在一条路径连接A,B,并且它的长度为C。

输出格式:

一个整数表示所有奶牛全都躲进牛棚所用的最少时间。如果无法使全部奶牛都躲进牛棚,输出-1。

输入输出样例

输入样例#1:

3 4

7 2

0 4

2 6

1 2 40

3 2 70

2 3 90

1 3 120

输出样例#1:

110

说明

样例解释

1号点的两只牛直接躲进1号牛棚,剩下的5只中,4只跑去2号点,还有一只从1->2->3,3号点的2只牛也直接躲进去,这样最慢的牛花费的时间是110。

数据范围

对于100%的数据,N<=200 M<=1500

思路分析

想到网络流不难。建一个超级源点连向每块田地,容量就是这块田里牛的数量。还要建一个超级汇点,从每块田地连向它,容量就是棚子所能容纳的牛数量。只要满流了(即总流量等于总牛数),就说明当前解可行。

然而,对于田地之间的边又该如何处理呢?这里是最容易想偏的。。。。。。

其实我第一眼以为是取最后一次最大费用

跑最小费用最大流,每条田地之间的边费用就是它们的长度。这样貌似可以哈

然而很快就把这种诡异的办法给自己推翻掉了。

例子很简单。。。。。。

这张图的意思是,有3块田,1、2处各有一头牛,2、3处各有一个容量为1的棚。如果建费用流的图,就会长这个样子对吧。

试想一下跑费用流会发生什么。。。。。。

第一次,由S->2->T,没有费用;

第二次,由S->1->2->3->T,费用为2,跑完了。

然而,滑稽了。事实上,我们可以让两头牛一起动,1->2,2->3,最大的费用只有1。

因为费用流每次把最短的挑走了,使我们反而找不到答案。所以万万不能跑费用流了。


对于这种无法直接建模的题目,考虑二分答案。把每两点之间的最短距离用Floyd算出来,然后两两连边,边的容量均为INF。每次二分最长时间的取值,只把边长(即花费时间的长度)小于等于当前mid的边加进去,然后跑最大流。如果流满了就说明可行,把上界调至当前mid。否则把下界调至mid+1。一次次来,直到找到最终答案。

然而,数据范围超过了int,每次二分还要重新加边,再跑一遍dinic,时限可不能这么玩的!

于是,有必要来减少二分次数了。

既然点数是有限的,那么它们两两相连所产生的边数也不多,顶多几万条。而longlong取值范围太大了,即使二分,也需要跑五六十下(假如没卡INF大小的话),卡了以后也还是不小。

所以,可以把边按长度离散化,在边的集合上进行二分。把点两两之间的最短距离用floyd算出来以后,按长度sort一下,再按次序加入边集合中。还要按照长度的取值范围分成若干个小集合(即离散化)。因为已经有序了,所以直接在离散化后的序列上二分就好了。

加上一个比较方便的做法。把每个值在边集中的对应位置也记录下来。二分完,跑最大流最小割的时候,在这个位置之后的边(也就是边长比mid大的边,因为sort加离散化后较长的边加在了后面)都直接跳过。这样做又省去了重新建边的时间。


然后我就WA了,连样例都没过

调试了下发现,当我二分到70的时候,居然满流了。。。。。。

原来我没拆点,结果1<->2长度40的边和2<->3长度70的边连起来了。。。。。。

所以一定要拆点!!!边加两次就是了。

边的容量可以不用开到INF了,等于起点对应的牛数量就可以了(从那里只能跑出那么多牛嘛)。说不定可以优化常数

附上样例建图

吐槽一句TM这题目数据范围也没给清楚

所以还是要开longlong的,实测开intWA一个点。。。。。。

具体细节就看下面代码吧。加了不少优化,32s成功冲到当前本题rank1开了O2,欢迎超越。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. typedef long long LL;
  6. #define R register int
  7. #define RL register LL
  8. const int N=1009,M=200009;
  9. const LL INF=1ll<<50;
  10. struct EDGE{
  11. int a,b;
  12. LL l;
  13. }e[M];//两点之间的连边存在这里排序
  14. int S=0,T,SZ,he[N],ne[M],to[M],q[N],d[N],cur[N],grp[M];
  15. LL LIM,f[M],mem[M],val[M],g[N][N];
  16. #define G c=getchar()
  17. #define in(z) G;\
  18. while(c<'-')G;\
  19. z=c&15;G;\
  20. while(c>'-')z*=10,z+=c&15,G;
  21. #define min(x,y) x<y?x:y
  22. #define min2(x,y) if(x>y)x=y
  23. #define add(U,V,F)\
  24. to[++p]=V;ne[p]=he[U];he[U]=p;mem[p]=F;\
  25. to[++p]=U;ne[p]=he[V];he[V]=p;
  26. inline bool cmp(EDGE x,EDGE y){return x.l<y.l;}
  27. inline bool bfs()
  28. {
  29. memset(d+1,0,SZ);
  30. for(R h=0,t=1;h<t;++h)
  31. for(R i=he[q[h]];i;i=ne[i])
  32. if(i<LIM&&f[i]&&!d[to[i]])
  33. d[q[t++]=to[i]]=d[q[h]]+1;
  34. return d[T];
  35. }//i<LIM忽略编号超过限制的边
  36. LL dfs(R u,RL mf)
  37. {
  38. if(u==T)return mf;
  39. for(R&i=cur[u];i;i=ne[i])
  40. if(i<LIM&&f[i]&&d[to[i]]==d[u]+1)
  41. {
  42. RL cf=dfs(to[i],min(f[i],mf));
  43. if(cf){f[i]-=cf;f[i^1]+=cf;return cf;}
  44. }
  45. return 0;
  46. }//以上是dinic模板
  47. int main()
  48. {
  49. R n,m,p=1,h=0,t=0,i,j,k,u,v;
  50. RL s,sum=0,res;
  51. register char c;
  52. in(n);in(m);T=n*2+1;SZ=(T+1)<<2;//S,T就是源汇点啦,SZ维护数组的长度
  53. for(i=1;i<=n;++i)
  54. {
  55. in(s);add(S,i,s);sum+=s;//统计一下牛的总数也就是总流量
  56. in(s);add(i+n,T,s);
  57. }
  58. for(i=1;i<=n;++i){add(i,i+n,mem[(i<<2)-2])};//mem之前存下了对应点的牛数
  59. for(i=1;i<=n;++i)
  60. for(j=1;j<i;++j)
  61. g[i][j]=INF;
  62. while(m--)
  63. {
  64. in(u);in(v);if(u<v){t=u;u=v;v=t;}
  65. in(s);min2(g[u][v],s);
  66. }
  67. for(k=1;k<=n;++k)
  68. for(i=1;i<=n;++i)
  69. {
  70. if(k==i)continue;
  71. s=k>i?g[k][i]:g[i][k];
  72. if(t==INF)continue;
  73. for(j=1;j<(min(k,i));++j)
  74. min2(g[i][j],s+g[k][j]);
  75. for(j=k+1;j<=i;++j)
  76. min2(g[i][j],s+g[j][k]);
  77. }//以上是Floyd,只用了半个矩阵,可能跑的快点吧
  78. for(i=1;i<=n;++i)
  79. for(j=1;j<i;++j)
  80. if(g[i][j]!=INF)
  81. e[h++]=(EDGE){i,j,g[i][j]};//加进去准备排序
  82. sort(e,e+h,cmp);
  83. s=0;
  84. for(i=0;i<h;++i)
  85. {
  86. if(s<e[i].l)//离散化,s放的是上一块的取值
  87. { //值增加了,处理上一块
  88. grp[t]=p+1;//grp记下取值在边集数组中对应位置
  89. val[t++]=s;//val记下上一块的值
  90. s=e[i].l;//更新s
  91. }
  92. add(e[i].a,e[i].b+n,mem[(e[i].a<<2)-2]);
  93. add(e[i].b,e[i].a+n,mem[(e[i].b<<2)-2]);
  94. }
  95. grp[t]=p+1;val[t++]=s;
  96. grp[t]=p+3;val[t]=-1;//收下尾
  97. h=1;
  98. while(h!=t)//二分开始
  99. {
  100. LIM=grp[m=(h+t)>>1];//确定限制,dinic时忽略编号超过此限制的边
  101. memcpy(f,mem,(p+1)<<3);//每次把记好的边流量copy一下再跑
  102. res=0;
  103. while(bfs())
  104. {
  105. memcpy(cur,he,SZ);//加当前弧优化
  106. while((s=dfs(S,INF)))
  107. res+=s;
  108. }
  109. sum==res?t=m:h=m+1;
  110. }
  111. printf("%lld",val[h]);
  112. return 0;
  113. }

洛谷P2402 奶牛隐藏(网络流,二分答案,Floyd)的更多相关文章

  1. 洛谷P2402 奶牛隐藏

    洛谷P2402 奶牛隐藏 题目背景 这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你.(奶牛混乱的原因看题目描述) 题目描述 在一个农场里有n块田地. ...

  2. [CodePlus 2017 11月赛&洛谷P4058]木材 题解(二分答案)

    [CodePlus 2017 11月赛&洛谷P4058]木材 Description 有 n棵树,初始时每棵树的高度为 Hi ,第 i棵树每月都会长高 Ai.现在有个木料长度总量为 S的订单, ...

  3. 洛谷P4589 [TJOI2018]智力竞赛(二分答案 二分图匹配)

    题意 题目链接 给出一个带权有向图,选出n + 1n+1条链,问能否全部点覆盖,如果不能,问不能覆盖的点权最小值最大是多少 Sol TJOI怎么净出板子题 二分答案之后直接二分图匹配check一下. ...

  4. 洛谷P3964 [TJOI2013]松鼠聚会 [二分答案,前缀和,切比雪夫距离]

    题目传送门 松鼠聚会 题目描述 草原上住着一群小松鼠,每个小松鼠都有一个家.时间长了,大家觉得应该聚一聚.但是草原非常大,松鼠们都很头疼应该在谁家聚会才最合理. 每个小松鼠的家可以用一个点x,y表示, ...

  5. 洛谷P3576 [POI2014]MRO-Ant colony [二分答案,树形DP]

    题目传送门 MRO-Ant colony 题目描述 The ants are scavenging an abandoned ant hill in search of food. The ant h ...

  6. 洛谷P1462通往奥格瑞玛的道路——二分答案最短路

    题目:https://www.luogu.org/problemnew/show/P1462 最大值最小问题,二分答案. 代码如下: #include<iostream> #include ...

  7. 洛谷3933 Chtholly Nota Seniorious 二分答案+贪心

    题目链接 题意 给你一个N*M的矩阵 (N,M <=2000)  把他分成两部分 使两部分的极差较大的一个最小  求这个最小值.然后分矩阵的要求是:每个部分内部的方块之间,可以通过上下左右相互到 ...

  8. 洛谷P1991无线通讯网[kruskal | 二分答案 并查集]

    题目描述 国防部计划用无线网络连接若干个边防哨所.2 种不同的通讯技术用来搭建无线网络: 每个边防哨所都要配备无线电收发器:有一些哨所还可以增配卫星电话. 任意两个配备了一条卫星电话线路的哨所(两边都 ...

  9. 洛谷P1462 通往奥格瑞玛的道路[二分答案 spfa 离散化]

    题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...

随机推荐

  1. css去除ios文本框默认圆角

    css去除ios文本框默认圆角 input, textarea {-webkit-appearance: none;}

  2. 【转】egametang框架简介

    讨论QQ群 : 474643097 1.可用VS单步调试的分布式服务端,N变1 一般来说,分布式服务端要启动很多进程,一旦进程多了,单步调试就变得非常困难,导致服务端开发基本上靠打log来查找问题.平 ...

  3. Mysql字符串截取总结:left()、right()、substring()、substring_index()

    同步首发:http://www.yuanrengu.com/index.php/20171226.html 在实际的项目开发中有时会有对数据库某字段截取部分的需求,这种场景有时直接通过数据库操作来实现 ...

  4. 2015年百度实习生前端笔试题上海卷a

    1.写出javascript运行结果:alert(‘5’+5); 结果:’55’ 2.写出javascript运行结果:for(var i=0; i<10; i++){} alert(i); 结 ...

  5. C# 快速高效率复制对象的几种方式

    http://www.cnblogs.com/emrys5/p/expression_trans_model.html 这篇较具体. 本文基于上文略加改动,暂记 using Newtonsoft.Js ...

  6. 使用Socket对序列化数据进行传输(基于C#)

    客户端代码 [Serializable] // 表示该类可以被序列化 class Person{ public string name; public void HI() { Debug.Log(na ...

  7. python语言基础语法笔记<note2--面向对象编程>

    Python面向对象编程(OOP) 一.面向对象过程的优点特征: 封装 模型的特征和能力打包在一起 模型的改变由模型自身完成 隐藏模型的细节,外界只能使用,不能改变 继承 符合自然界分类规律 快速实现 ...

  8. Hibernate5环境搭建

      1.导包 Hibernate开发包   数据库的驱动包   2.核心配置文件   核心配置文件(赋值到src下) 1.核心配置文件 对于hibernate的核心配置文件它有两种方式(选其中一种即可 ...

  9. SecureCRT8.0设置语法高亮

    SecureCRT默认不显示语法高亮,整个界面颜色单一,用起来很不舒服,也没有效率,所有通过设置一下语法高亮还是很有必要的, 默认字体也看着不是很清晰.所以还是修改一下预告高亮比较好 设置语法高亮,多 ...

  10. Jetty添加Filter过滤器

    1.Jetty嵌入到Spring项目 try { Server server = new Server(8080); WebAppContext context = new WebAppContext ...