洛谷P2402 奶牛隐藏(网络流,二分答案,Floyd)
了解网络流和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,欢迎超越。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
#define R register int
#define RL register LL
const int N=1009,M=200009;
const LL INF=1ll<<50;
struct EDGE{
int a,b;
LL l;
}e[M];//两点之间的连边存在这里排序
int S=0,T,SZ,he[N],ne[M],to[M],q[N],d[N],cur[N],grp[M];
LL LIM,f[M],mem[M],val[M],g[N][N];
#define G c=getchar()
#define in(z) G;\
while(c<'-')G;\
z=c&15;G;\
while(c>'-')z*=10,z+=c&15,G;
#define min(x,y) x<y?x:y
#define min2(x,y) if(x>y)x=y
#define add(U,V,F)\
to[++p]=V;ne[p]=he[U];he[U]=p;mem[p]=F;\
to[++p]=U;ne[p]=he[V];he[V]=p;
inline bool cmp(EDGE x,EDGE y){return x.l<y.l;}
inline bool bfs()
{
memset(d+1,0,SZ);
for(R h=0,t=1;h<t;++h)
for(R i=he[q[h]];i;i=ne[i])
if(i<LIM&&f[i]&&!d[to[i]])
d[q[t++]=to[i]]=d[q[h]]+1;
return d[T];
}//i<LIM忽略编号超过限制的边
LL dfs(R u,RL mf)
{
if(u==T)return mf;
for(R&i=cur[u];i;i=ne[i])
if(i<LIM&&f[i]&&d[to[i]]==d[u]+1)
{
RL cf=dfs(to[i],min(f[i],mf));
if(cf){f[i]-=cf;f[i^1]+=cf;return cf;}
}
return 0;
}//以上是dinic模板
int main()
{
R n,m,p=1,h=0,t=0,i,j,k,u,v;
RL s,sum=0,res;
register char c;
in(n);in(m);T=n*2+1;SZ=(T+1)<<2;//S,T就是源汇点啦,SZ维护数组的长度
for(i=1;i<=n;++i)
{
in(s);add(S,i,s);sum+=s;//统计一下牛的总数也就是总流量
in(s);add(i+n,T,s);
}
for(i=1;i<=n;++i){add(i,i+n,mem[(i<<2)-2])};//mem之前存下了对应点的牛数
for(i=1;i<=n;++i)
for(j=1;j<i;++j)
g[i][j]=INF;
while(m--)
{
in(u);in(v);if(u<v){t=u;u=v;v=t;}
in(s);min2(g[u][v],s);
}
for(k=1;k<=n;++k)
for(i=1;i<=n;++i)
{
if(k==i)continue;
s=k>i?g[k][i]:g[i][k];
if(t==INF)continue;
for(j=1;j<(min(k,i));++j)
min2(g[i][j],s+g[k][j]);
for(j=k+1;j<=i;++j)
min2(g[i][j],s+g[j][k]);
}//以上是Floyd,只用了半个矩阵,可能跑的快点吧
for(i=1;i<=n;++i)
for(j=1;j<i;++j)
if(g[i][j]!=INF)
e[h++]=(EDGE){i,j,g[i][j]};//加进去准备排序
sort(e,e+h,cmp);
s=0;
for(i=0;i<h;++i)
{
if(s<e[i].l)//离散化,s放的是上一块的取值
{ //值增加了,处理上一块
grp[t]=p+1;//grp记下取值在边集数组中对应位置
val[t++]=s;//val记下上一块的值
s=e[i].l;//更新s
}
add(e[i].a,e[i].b+n,mem[(e[i].a<<2)-2]);
add(e[i].b,e[i].a+n,mem[(e[i].b<<2)-2]);
}
grp[t]=p+1;val[t++]=s;
grp[t]=p+3;val[t]=-1;//收下尾
h=1;
while(h!=t)//二分开始
{
LIM=grp[m=(h+t)>>1];//确定限制,dinic时忽略编号超过此限制的边
memcpy(f,mem,(p+1)<<3);//每次把记好的边流量copy一下再跑
res=0;
while(bfs())
{
memcpy(cur,he,SZ);//加当前弧优化
while((s=dfs(S,INF)))
res+=s;
}
sum==res?t=m:h=m+1;
}
printf("%lld",val[h]);
return 0;
}
洛谷P2402 奶牛隐藏(网络流,二分答案,Floyd)的更多相关文章
- 洛谷P2402 奶牛隐藏
洛谷P2402 奶牛隐藏 题目背景 这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你.(奶牛混乱的原因看题目描述) 题目描述 在一个农场里有n块田地. ...
- [CodePlus 2017 11月赛&洛谷P4058]木材 题解(二分答案)
[CodePlus 2017 11月赛&洛谷P4058]木材 Description 有 n棵树,初始时每棵树的高度为 Hi ,第 i棵树每月都会长高 Ai.现在有个木料长度总量为 S的订单, ...
- 洛谷P4589 [TJOI2018]智力竞赛(二分答案 二分图匹配)
题意 题目链接 给出一个带权有向图,选出n + 1n+1条链,问能否全部点覆盖,如果不能,问不能覆盖的点权最小值最大是多少 Sol TJOI怎么净出板子题 二分答案之后直接二分图匹配check一下. ...
- 洛谷P3964 [TJOI2013]松鼠聚会 [二分答案,前缀和,切比雪夫距离]
题目传送门 松鼠聚会 题目描述 草原上住着一群小松鼠,每个小松鼠都有一个家.时间长了,大家觉得应该聚一聚.但是草原非常大,松鼠们都很头疼应该在谁家聚会才最合理. 每个小松鼠的家可以用一个点x,y表示, ...
- 洛谷P3576 [POI2014]MRO-Ant colony [二分答案,树形DP]
题目传送门 MRO-Ant colony 题目描述 The ants are scavenging an abandoned ant hill in search of food. The ant h ...
- 洛谷P1462通往奥格瑞玛的道路——二分答案最短路
题目:https://www.luogu.org/problemnew/show/P1462 最大值最小问题,二分答案. 代码如下: #include<iostream> #include ...
- 洛谷3933 Chtholly Nota Seniorious 二分答案+贪心
题目链接 题意 给你一个N*M的矩阵 (N,M <=2000) 把他分成两部分 使两部分的极差较大的一个最小 求这个最小值.然后分矩阵的要求是:每个部分内部的方块之间,可以通过上下左右相互到 ...
- 洛谷P1991无线通讯网[kruskal | 二分答案 并查集]
题目描述 国防部计划用无线网络连接若干个边防哨所.2 种不同的通讯技术用来搭建无线网络: 每个边防哨所都要配备无线电收发器:有一些哨所还可以增配卫星电话. 任意两个配备了一条卫星电话线路的哨所(两边都 ...
- 洛谷P1462 通往奥格瑞玛的道路[二分答案 spfa 离散化]
题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...
随机推荐
- pip install 提示"no previously-included directories found matching"及"no previously-included files matching found anywhere in distribution",且偶发无法关联安装 PyPI 库的故障
环境描述: Python 2.7.5 CentOS-7.2 报错现象: (1).在虚拟环境下运行 pip install 命令安装 PyPI 第三方库,出现类似如下告警. Running setu ...
- win7局域网共享文件
调整共享文件所在电脑设置: 1. 关闭防火墙 2. 更改网络设置 ①打开网络和共享中心 ②进入"选择家庭组和共享选项" ③进入"更改高级共享设置" ④调整设置并 ...
- Mybatis 动态使用update语句
update pf_product_audio_t <trim prefix="set" suffixOverrides=","> <if t ...
- ECharts 高度宽度自适应(转载)
最近在写一个地图类的应用,用的是echarts的图表,然而一上来就一脸懵逼,如果父级容器的height/width属性设置为百分比的形式,那么echarts就会warning,且不能正常的生成图表.所 ...
- js “top、clientTop、scrollTop、offsetTop…”
当要做一些与位置相关的插件或效果的时候,像top.clientTop.scrollTop.offsetTop.scrollHeight.clientHeight.offsetParent...看到这么 ...
- 【转】磁盘I/O那些事
背景 计算机硬件性能在过去十年间的发展普遍遵循摩尔定律,通用计算机的CPU主频早已超过3GHz,内存也进入了普及DDR4的时代.然而传统硬盘虽然在存储容量上增长迅速,但是在读写性能上并无明显提升,同时 ...
- Android Stdio 中的Rendering Problems Android N requires the IDE to be running with Java 1.8 or later Install a supported JDK解决办法
出现如下图所示的错误 解决办法为: 然后在里面输入SDK 下载 下载APILevel为23版本的SDK 换成23版本的SDK 完美解决问题
- Winform下去除MDI窗体边框
做项目中间遇到了MDI窗体内边框的问题,经过苦苦寻找,最终得到了解决方案 在Main窗体中调用API // Win32 Constants ; ; private const int WS_BORDE ...
- nyoj888 取石子(九) 反Nimm博弈
这题就是反Nimm博弈--分析见反Nimm博弈 AC代码 #include <cstdio> #include <cmath> #include <algorithm&g ...
- HttpURLConnection 411错误解决
1.问题描述 Java HttpURLConnection类发送Http请求链接外网返回ResponseCode为411,对方为.NET服务器,网上查明原因可能来自以下: 1.可能是没有传http中的 ...