04/16
一共做了8道题
首先网络流目前自己掌握的只有最大流Dinic算法和普通的费用流算法
有空还要去学习一下SAP和ZKW费用流(flag早早立在前面以后看到都有动力...
但网络流的算法个人认为并不重要,解题的关键和思维的难点都在建图上
所以这一类的题目往往将模板一打,剩下的代码就非常短
将看起来毫无关系的题目转化成网络流做十分有趣
BZOJ3931 CQOI2015网络吞吐量
题目描述
路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点。网络中实现路由转发的硬件设备称为路由器。为了使数据包最快的到达目的地,路由器需要选择最优的路径转发数据包。例如,在常用的路由算法OSPF(开放式最短路径优先)中,路由器会使用经典的Dijkstra算法计算最短路径,然后尽量沿最短路径转发数据包。
现在,若已知一个计算机网络中各路由器间的连接情况,以及各个路由器的最大吞吐量(即每秒能转发的数据包数量),假设所有数据包一定沿最短路径转发,试计算从路由器1到路由器n的网络的最大吞吐量。计算中忽略转发及传输的时间开销,不考虑链路的带宽限制,即认为数据包可以瞬间通过网络。路由器1到路由器n作为起点和终点,自身的吞吐量不用考虑,网络上也不存在将1和n直接相连的链路。
首先根据题目描述跑一遍最短路,求出哪些边是可能传输的(可能不止一条边)
关于最大吞吐量直接拆点变成两点之间的边容量限制
注意起点和终点不能有边容量限制
然后直接最大流就可以了
BZOJ1001 BEIJING2006 狼抓兔子
现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦.
这道题题意是让我们计算最小割,但是由于点和边均很多,跑最大流显然会超时
于是引出了平面图的最小割的一种快速做法——转化成对偶图跑最短路
我们将平面图中的每个面看成一个点,分割两个面的边看成连接两个点的边,将s和t的一侧无界面看做起点,另一侧看做终点
那么答案就是求这个新图上起点到终点的最短路,非常好理解!
但是这道题调了很久的原因需要引起重视
一般读图的时候每行读完我都会写“readln”,但是这道题当m=1的时候是没有图可以读的但是由于n>1所以readln仍然会做
这个时候就出现了问题...以后readln要慎写
1834: [ZJOI2010]network 网络扩容
Description
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。
第一问是非常显然的最大流,然后第二问肯定是用费用流做
我们对于每条边建一条容量为c,费用为0的边,再建一条容量为+无穷,费用为w的边
然后从源点流出原先的最大流+k的流量,做一遍最小费用最大流就可以了
1066: [SCOI2007]蜥蜴
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。
一只蜥蜴可以看做是流量为1的水流,因为经过的点容量都会减1,然后拆点,加上一条容量为石柱高度的边
汇点为所有在图外的点。跑最大流即可。
1877: [SDOI2009]晨跑
Description
Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑。 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校,保证寝室编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以 在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路 口。Elaxia耐力不太好,他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天 数尽量长。 除了练空手道,Elaxia其他时间都花在了学习和找MM上面,所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。
这道题描述就是裸的最小费用最大流...拆点不过起点和终点不能拆...
注意一个细节就是当n=2的时候,由于1和n均没有限制所以原来的程序会输出+无穷,要特判输出1,或者将边的容量设为1
(当然边的容量设为1较好..因为实际上我们本需要把边的容量设为1,只是由于经过两点都只有1次边肯定一次因而略去
如今这个基础不复存在我们就需要处理它,特判终究是用来弥补程序缺陷的东西)
1189: [HNOI2007]紧急疏散evacuate
Description
发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是‘.‘,那么表示这是一块空地;如果是‘X‘,那么表示这是一面墙,如果是‘D‘,那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。
这道题以前就在张老师那里做过,每个人和每个门的每个可行的时间连边,然后二分图最大匹配,当然这里我用最大流来做
题目问的是最短需要多少时间,于是我们二分答案,每次重新建图
对于网络流重新建图的问题,一般在套用模板外面的时候注意两点:
1)next和link两个数组清零,否则有很大概率会死循环
2)e清零,当然这个不容易忘...
1305: [CQOI2009]dance跳舞
Description
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
这道题刚开始想了很久都没有想出来应该怎么做...
建图是以前没有遇到过的类型...果然是很有趣的题
每个点i再拆出两个点ix,iy,ix表示点i和喜欢的女生连,iy表示点i和不喜欢的女生连
对于女生也同样
然后每个点i向ix连出容量为n的边,向iy连出容量为k的边,女生也一样
(ix,jx),(iy,jy)之间分别连边,容量为1
然后s点向每个i点连出容量为舞曲数目的边,j点向t也一样连容量为舞曲数目的边
当源点流出的水都流到汇点说明这个舞曲数目是可以达到的
二分答案即可
1221: [HNOI2001] 软件开发
Description
某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员每天提供一块消毒毛巾,这种消毒毛巾使用一天后必须再做消毒处理后才能使用。消毒方式有两种,A种方式的消毒需要a天时间,B种方式的消毒需要b天(b>a),A种消毒方式的费用为每块毛巾fA, B种消毒方式的费用为每块毛巾fB,而买一块新毛巾的费用为f(新毛巾是已消毒的,当天可以使用);而且f>fA>fB。公司经理正在规划在这n天中,每天买多少块新毛巾、每天送多少块毛巾进行A种消毒和每天送多少块毛巾进行B种消毒。当然,公司经理希望费用最低。你的任务就是:为该软件公司计划每天买多少块毛巾、每天多少块毛巾进行A种消毒和多少毛巾进行B种消毒,使公司在这项n天的软件开发中,提供毛巾服务的总费用最低。
这道题是网络流的一类经典问题:餐巾计划问题
我们对于每一天拆成两个点,分别表示这一天需要的餐巾x和这一天用过的餐巾y
源点表示买餐巾的提供商,首先s向x肯定要连边
按照最初的想法,希望x向y连边再连回之后的x,但是发现这种想法非常不现实
最小费用最大流首先保证的就是最大流,这种重复利用并没有增加流量因此是不可能出现的
这个思路提醒我们:消毒也要从源点流出流量
所以我们想到了源点连向y点,再从y点连向可以传递的x点
源点连向y点的容量为当天需要的餐巾数,这个时候的s我们不能把它理解为餐巾提供商了
我们可以把它理解为该y点对应的x点,用完的餐巾=当天需要的餐巾=可以传递下去的餐巾
每个x点再向t点连当天需要餐巾数的边,用来限制流量
然后就是传递的问题了,刚开始的想法是对于a+1天以后的天都连边,也就是n^2建边?
有点虚啊...毕竟网络流的算法复杂度并不优到能承受m=10^6+
然后突然发现好像和NOIP DAY1T3有点相似...小鸟不是也可以飞到更低(还是更高?)的地方吗
我们只需要在当前状态往上或往下传递就可以了,小鸟的那道题只需要在当前柱子不停往下的时候加一句O(1)的传递
这道题也是一样,对于每一个y点只需要向它下面一天的y点连一条边就可以了
这样这道题就差不多解完了,感觉非常巧妙
Summary:
网络流的题目都很锻炼思维,可能较于一些数据结构题而言更适合我
当然这些建图需要非常强的观察能力和建模能力
与其将希望寄托于考场时的灵光闪现
不如多做一些题目来拓宽思维积累经验
另外,今天尝试了一下一天结束再写题解的方法
个人认为不是特别好..因为一些做题中遇到的细节都已经忘了
还是随手写题解(或者代码旁边写注释也可以
当然网络流的题目还是当场写题解的好
可以一天里最后集到一起发,也可以一部分一部分加
明天开始改正