最近一直很忙,为了节省时间,从今以后的题解会 一个专题 写一篇。
刷了一些题后,有了以下总结:
模型要点:
1.构造流量平衡,在满足流量平衡的情况下,找到要让什么最大。
2.一般用于判断性问题,即所有从源点流出的边满流(或者所有流入汇点的边满流)的时候可行.所以往往和二分答案结合起来使用。
3.如果答案假设为i+1的时候的图仅仅比假设答案为i的时候的图多了一些点或者边,那么可以在假设答案为i的图 跑过最大流后,加上相应的点和边,继续跑最大流.这样顺序枚举答案,避免了每次重新做最大流和重新构图,许多时候效率比二分答案高。
相关题目:
1.飞行员配对方案 (网络流24题):
题解:
二分图匹配的模型.
2.最小路径覆盖(网络流24题):
题解:
由于是DAG,可以发现选取路径数等于顶点数减去选取的边数。每个点只能在一条路径上,因此除了起点和终点,每个点的入度出度都为1. 因此转化为二分图,把每个点i拆成2个点<si,ti>(分别表示点i的入度和出度),对于每条边<i,j>,连边<ti,sj>(让i出度和j入度+1). 然后连<S,ti> <si,T>,每个点的入度出度都只能用一次,那不就是二分图匹配的模型了? 如果要输出方案,找到所有si没有匹配的点(即没有入度)当做起点,沿着匹配边dfs寻找就可以了.
3.魔术球(网络流24题):
题目大意:有n根柱子,在这n根柱子中依次放入编号为1,2,3,……的球,每次只能在某根柱子的最上面放球,在同一根柱子中,任何2个相邻球的编号之和为完全平方数。求在n根柱子上最多能放多少个球。
题解:
注意题目中是依次放,所以编号小的只能放在编号大的下面。所以对于球i,找到所有满足(i+j)是完全平方数且j>i的球j,连一条边<i,j>. 然后二分答案,做最小路径覆盖与n比较。 这样做的前提是按编号从小到大放球,可见题中"依次"的重要性。
4.最长递增子序列(网络流24题)
题目描述:
给定正整数序列x1, x2, ..., xn。
(1)计算其最长递增(非降,允许有相等元素)子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。
题解:
这题当时没想出来,构图挺巧妙的.
第一问:dp就不多说了,F[i]表示以i结尾的LIS。
第二问:利用第一问dp的数组。 对于任意i<j,只有当 A[i]<A[j] 且 F[i]+1==F[j]的时候才连边<i,j>。由于每个点只能用一次,所以拆成两个点,增加点流量限制为1.
第三问:只要去掉第二问中 点1和点N的流量限制就可以了。
5.星际转移问题(网络流24题)
题目大意:
有N个人在地球(源点S),要用公交飞船送到(汇点T),然后告诉你每个飞船的周期和路线,求最少要多少天完成目标。
题解:
这题让我第一次接触了分层图的思想。如果不拆点,那么没法表示边,因为根据周期边是会"跑"的。根据lrj《训练指南》上的做法,假设答案是k天,那么把一个点拆成k+1个点,即表示第i天这个点的状态。 那么就可能根据公交飞船的周期和路线来连边.比如有一个飞船,第3天在i点,第4天在j点,那么连边<i3,j4>.做最大流判断是否能达成目标就可以了。 至于k,二分或者枚举都可以,但是枚举应该会快一些。
6.Ombrophobic Bovines(poj 2391)
题目大意:
有一些牛分别在一些点上,然后有一些边,表示相邻的点之间相互到达的时间,求最短的时间使得所有的点上都有牛。
题解:
首先做一次floyd,把原始边转化为最短路边,记为dist[i][j]。其次可以转化为判定性问题,二分或者枚举最短的时间ans.判断ans是否可行, 只要拆点i为<si,ti>,
然后对于所有dist[i][j]<=ans的边<i,j> 加边 <ti,sj> , 对于本来就有牛的点,加边<S,si> , 然后每个点加边<ti,T> <si,ti> 做最大流看与汇点连接的弧是否都满流。
ps:如果用枚举,不是每次+1,而是事先把dist排序,然后依次枚举。实践证明,枚举比二分稍微快了点。
7.Sightseeing tour(poj 1637)
题目大意:
混合图判断是否存在欧拉回路。
题解:
存在欧拉回路的充要条件是每个点的入度和出度相等。那么对于无向边,先随便给它定个方向,然后统计每个点的入度出度。记点i的入度出度分别为为xi,yi。
由于每个点的xi+yi是固定的(不随无向边的方向改变而改变,如果是奇数必定无解),因此对于yi>xi的点,必须把和它相连的且起点定为它的无向边反向(yi-xi)/2个才能使入度出度相等(当然也可以把终点定为它的无向边反向,只要最终结果是这样即可)。同理对于xi>yi的点,必须把和它相连的且终点定为它的无向边反向(yi-xi)/2个才能使入度出度相等。 那么就可以构造网络G,对于yi>xi的点,连边<S,i,(yi-xi)/2> 对于xi>yi的点,连边<i,T,(xi-yi)/2>,对于每一条人为定向为<i,j>的无向边,连边<i,j,1>,跑最大流判断是否满流即可。
8.PIGS(poj 1149)
题目大意:
有一些猪圈,然后依次来了一些顾客,分别会打开一些猪圈并买走一些猪(有买的上限),对于每个顾客,他来买的时候 被打开的猪圈里的猪可以跑到其他被打开的猪圈里,他买完了就不行了。问最多能卖多少头猪。
题解:
如果一个顾客光顾的猪圈集合为{x,P},那么x的下一个顾客就可以买到{x,P}里的猪。 因此先预处理出每个猪圈会被那些顾客打开(按顺序),以顾客为节点,对于猪圈x的第一个顾客x1,连边<S,x1,pig[x]> ,pig[x]为一开始猪的数量。对于其他顾客,连边<xi,xi+1,inf> 然后每个顾客连边到汇点,容量为买的上限。跑最大流就是答案。
9.The Maximum Number of Strong Kings(poj 2699)
题目大意:
n个人两两之间打比赛(竞赛图),赢的人加一分,一个人是Strong King当且仅当他的得分最高或者他打败了所有比他分数高的人。给出每个人的得分,求最多能有多少个Strong Kings.
题解:
网络上很多人都说假设答案是ans,那么一定存在某个方案,使得得分最高的ans个人是Strong Kings,但是大多都是含糊的说概率比较大什么的,我只在一篇博文里看到了证明 http://blog.csdn.net/sdj222555/article/details/7797257 ,但是感觉也不大严谨 , 一定是我太弱了。
最保险的做法还是二进制枚举 Strong Kings 。
然后是构图,构造二分图,一边表示比赛,一边是选手。对于不是Strong Kings的选手i,j之间的比赛 k, 连边<S,k,1><k,i,1><k,j,1>,如果选手i是Strong Kings,看他的对手得分j是不是比他大,如果比他大,那就不连<k,j>. 然后每个选手连边到汇点,容量为其得分。 跑最大流 看是否满流。