码迷,mamicode.com
首页 > 其他好文 > 详细

网络流小结

时间:2015-10-08 14:36:44      阅读:280      评论:0      收藏:0      [点我收藏+]

标签:

一, 最大流

  1)拆点

    ①满足个体自身的限制

 

    POJ 3281  Dining

    最多多少奶牛可以选到心仪的食物和饮料。 因为每个奶牛对答案的贡献至多为一, 所以把每头奶牛拆成两个点, 连一条容量为一的边就可以了。

 

    SPOJ 962  Intergalactic Map

    这道题告诉我们网络流可以求 是否存在一条经过 每一个点(每一条边)不超过 k 次的路径。 只需要把每个点都拆成两个点, 中间连一条容量为 k 的边就可以了。

 

    1305: [CQOI2009]dance跳舞

    每个人最多和 k 个不喜欢的人跳舞。 把每个人拆成连喜欢的和连不喜欢的两个点, 两点之间有一条容量为 k 的边。

 

    SGU 438      The Glorious Karlutka River =)

    每块石头都要拆成 2 * t 块,在每一个不同的时间点都用两个点表示, 两点间容量为 ci, 第二个点向所有它能到的点的下一个时刻 的第一个点 连一条容量为 ∞ 的边。

    上述问题解决的都是 对 某一个个体单独的 数量上的要求, 不会影响到整体, 那么就在这个个体内部拆点然后再把它 加到整体的网络流中。

 

 

    ②代表着时间(空间)转移后的不同情况。

 

    SGU 438      The Glorious Karlutka River =)

    每块石头都要拆成 2 * t 块,在每一个不同的时间点都用两个点表示, 两点间容量为 ci, 第二个点向所有它能到的点的下一个时刻 的第一个点 连一条容量为 ∞ 的边。

 

    POJ 2391  Ombrophobic Bovines

    这题比较简单, 每个点拆成两个点即可, 分别表示 移动之前的状态 和移动之后的状态。

  2)分配

    ① 比赛问题

    WOJ  1124  Football Coach

    每场比赛是一个点, 每个人是一个点, 每场比赛向源点连一条2的边, 向两个比赛者各连一条2的边就可以啦。

 

    SGU 326  Perspective

    类似上一题哒

 

    POJ 2699    The Maximum Number of Strong Kings

二分 k 的大小后 (这里网上的题解多半在扯一个明显错误的结论, 如果最终答案为 k 是可行的, 容易证明必存在一组解使得 最大的k个人满足要求, 而不是满足要求的解必须取最大的 k 个人), 同样是每场比赛开一个点, 每个人开一个点, 因为确定了最大的 k 个人是 strong king , 有些比赛的 胜负是已定的, 未确定的各连一条边就好了, 看最大流是否满流。

 

    这类题大多要给每一场比赛开一个点, 然后想办法 把 这场比赛 结束后 出现的每一种可能都 加到图上。

 

    ② 其它分配

    这类问题和比赛问题大同小异。

    JOJ 2453  Candy

每一颗糖就像一场比赛, 不同的处理方案可以导致不同的结果, 糖可以分给每一个小朋友而比赛的赢家可以分给参与者之一。 最后看可不可以满足方案就是给每一个小朋友都向汇点连一条至少为那么多才满足条件的边, 如果最大流是满流显然有可行方案, 否则没有。

 

  3)建图

    ① 选择性的建边

    ZOJ 2760    How Many Shortest Path

问有多少条不互相重合的最短路。 一条边[i, j]可能是任意一条最短路上的边 当且仅当 dist[s, i] + [i, j] + dist[j, t] == 最短路的长度。 把这些这些边分别建到流网络中, 每条边的容量为一, 跑一边就好了。

 

     ② 需要优化的构造

     POJ  1149  PIGS

    /******** 来自Edelweiss  《网络流建模汇总》********

    规律1.  如果几个结点的流量的来源完全相同,则可以把它们合并成一个。
规律2.  如果几个结点的流量的去向完全相同,则可以把它们合并成一个。
规律3.  如果从点u 到点 v 有一条容量为∞的边,并且点v 除了点 u 以外没
有别的流量来源,则可以把这两个结点合并成一个。

    在面对网络流问题时,如果一时想不出很好的构图方法,不如先构造一个最
直观,或者说最“硬来”的模型,然后再用合并结点和边的方法来简化这个模
型。经过简化以后,好的构图思路自然就会涌现出来了。这是解决网络流问题
的一个好方法。

    *******************************************************/

这样的题, 或是应用规律 把 原本复杂的问题优化掉, 或是直接就把握到了问题的本质建出一个优美的图,,感觉都很有难度呢,,还是要多做题,,

 

  4)技巧

    ① 二分出 某一条(些)边的容量

    二分已确定 在满足 有可行解的情况下某一条(些)边的容量的最大(小)值是多少。

    SPOJ 287  Smart Network Administrator

     问在可以实现满流的情况下, 流量最大的一条边 流量最小是多少。 这样想很容易想到要 二分出那个最小的最大值, 然后所有边都赋成这个值判是否可行。

 

    ②利用 流守恒性

     POJ 1637   Sightseeing tour

求混合图的 欧拉回路。 欧拉回路的 充要条件是每个点的入度等于出度, 恰好和 网络流 的流守恒性 不谋而合。每条无向边 会给两个顶点 一个入度加一, 一个出度加一, 觉不觉得这和一场比赛有些像! 更好的方法是先把每条无向边随意定向, 然后把一个点多出来 的入度 给 少入度 的 和它连边的点, 这样就少了每个边的点就会快很多。

    发现比赛的模型也可以这么做, 先假设一方赢, 然后进行调整。如果另一方赢了 就流一条2 的边, 如果是平局就流一条 1 的边, 应该可以的。

 

 

二, 最小割

 

一切严谨证明 见 amber hbt的 《最小割模型在信息学竞赛重的应用》一文。 下面是一些我自己粗浅的理解。

 

割, 即把所有的点 分成 S 和 T 两部分, 每个点存在 且 仅存在于 S 中 或 T 中, 并且 源点 属于 S, 汇点属于T。

割与流的关系: 流网络中的一个流 经过 一个割的静流 就是它 的流量。

证明:

先明确 : ① 自己流向自己 的流量总和 为0。 ② 所有非源非汇的点 流量 的总和 都是 0。

那么 f(S, T) = f(S, V) - f(S, S) = f(S, V) = f(s, V) + f(S - s, V) = f(s, V) = f(s, t)。

最大流最小割定理: 顾名思义 , 一个网络中的最大流 等于 它的最小割容量。

感性 证明: 想象 一堆流 流啊流啊, 流到 最小割的割边的前面一起停住了, 接着向前流的时候, 只能 流过 最小割的容量 那么多了, 再多了就流不过去了, 所以这一定是最大解; 而在它 流经 这步之前 和流经 这步之后 流经的所有割 都比它大, 所以这一定是最小解。 综上, 最大流 就 等于 最小割了。

 

分数规划

!!!!!!!!!!!!!!!!!!

 

待填坑

 

!!!!!!!!!!!!!!!!!!

 

最大权闭合图

闭合图就是说 这个图中的任意一个点 都没有一条 连向这个点之外的出边。

 

#define 简单割 所有割边都只连向s 或 只连向 t 的割。

 

给这张图 s 向 所有正权值的点 连一条边, 流量为 vi, 所有负权值的点 向 t 连一条边, 流量为 -vi, 其它边不动, 流量为 ∞。

所以这张建好了图 的简单割的割边 是 不含原图中的任意一条边的(这点很重要)

 

下面, 这张图中的简单割 一定是一个闭合图, 所有闭合图也一定是一个简单割。

闭合图对应简单割:

如果闭合图 不对应一个简单割 的话, 在闭合图中就一定会有一条 从 S - s 中的一个点 到 T - t 中的一个点的边, 这条边连到了闭合图的外面, 矛盾。

简单割对应闭合图:

因为这张建好了图 的简单割的割边 是 不含原图中的任意一条边的, 所以在 简单割中, S - s 的所有点都不会连到 T - t 中去的, 所以是闭合图。

 

一个简单割的容量 就是 S - s 中的负权值的点的绝对值之和 + T - t中的正权值的点的绝对值 之和。

技术分享

 

当简单割 取最小时, 闭合图有最小值。

技术分享

 

所以就可以用最小割来求 最大权闭合图啦!! ^_^

 ,,,,,,,,终于完了,,到后面懒得自己写白话版的证明了因为hbt公式版的证明也很简单。

最大权闭合图的应用还是非常广 的。

题目描述中一般有的 tag :

正权 负权, 最大(最小)

例题:

① bzoj 1497: [NOI2006]最大获利  裸的题

② poj 2987 firing

这道题是要在保证 求出的闭合图 最大的前提下 求出点数最小的是多少。

可以证明如果求出最大权闭合图之后遍历一遍可以得到 最小的点数。

但是还有一种fantasy 的想法:

在网络中放大边权,将边权*10000,如果边和源点S连,那么流量减一,如果边和汇点T连,那么流量加一,对于原图中点权为0的点,与汇点T连,流量为1

设 与源点S连的边有total个,求得的最小割为max_flow,那么(max_flow+total)/10000就是原来的最小割, (max_flow+total)%10000就是DAG图中的取点数,因为在割边集中,如果割边和源点S相连,表示这个点不取,割边与汇点T相连,表示 这个点要取,所以采用上面的建图方法可以保证取得的就是最优解

这样做实在是很巧妙啊, 值得积累!

③ bzoj 1565: [NOI2009]植物大战僵尸

很有趣的一道题, 最大权闭合图还是挺显然的, 但是图中可能会有环! 环里的所有点 以及 环里所有点的前驱 都是不可能被攻击到的, 于是还要想办法消去这些点。 想到给 这个图的反向图进行拓扑排序, 那么所有可以拓扑到的点就是 最后可以选的点了。

最后还有一个小 tip:

dinic  在写 dfs 的时候要加上这一句话:

if(!f) dist[v] = 0;

这样就可以快好多。因为如果 dfs 发现 前面的容量已经都满了的话以后就不用再去找它可不可以增广了。

④ bzoj 2127

 /////////////////////////////////////////

非常不开心!! 我这里有七八道题解都被博客园吞掉了!!!简直,,,唉也没心情再补上了

//////////////////////////////////////////

 

一些 tips:

无向边。有一个很有用的作用:若A<-->B:C,即A与B连一条权值为C的无向边,当这条无向 边计入最小割时,表示这两个点分属于s,t两个集合。

 

vfleaking在贴吧中说:

 

如果v向u连一条容量为w的有向边,表示v如果在S割,那么u不在S割会产生w的代价。
一个等价的表述是,u如果在T割,那么v不在T割会产生w的代价。注意v如果在T割,那么u在S割是不会产生代价的。
特别的,如果v向u连一条容量为正无穷大的有向边,表示v如果在S割,那么u一定也要在S割。
一个等价的表述是,u如果在T割,那么v一定也要在T割。

具体是单向边还是双向边取决于你要实现的功能。

 

总结一下, 最小割建图中的边呢, 主要有这几种 :

  • 一个点连向 源 或汇, 这代表让这个点分到第一类/ 第二类的代价。
  • 有向边 u -> v , u 在 S 而 v 不在的代价。
  • 有向边 u -> v (c = INF)  : ① u,v 同属一侧  ②u, v需要割掉其中的一个
  • 无向边 u <-> v : u, v 不在同一集合需要付出的代价。
  • 点权可以转移到与源或汇相连的边权上, 一遍充分理由最小割这个最优化工具来决策点权的取舍。< /span>

 

 看一下这样的一张图:

技术分享

这张图的割会有如下几种情况:

 ① 割 SA & SB  或者 割 AT & BT

  这时代表着A ,B 被分到了 同一组里, 各花费各自的代价。

② 割 SA & AB & BT  或者 割SB & BA & AT

  这时代表着 A, B 没有被分到同一组里, 需要花费 各自的代价还有 他们 在同一组里时的代价。

 

【bzoj2132】圈地计划

既然知道这是一道最小割的题了, 那么要求收益最大? 求补集。

把所有可能的收益加起来, 然后再减去最小的花费就可以了。 显然, 一个点建工业区就要花费商业区的钱, 建商业区就要花费工业区的钱, 另外如果相邻的相同就还要花费 cij 的钱。 前面两个条件直接上源点和汇点连边就好了, 那么第三中情况呢? 注意我上面的总结 , 两点间的一条无向边代表着它们不在同一集合里的时候需要花费的代价, 那么如何处理在同一集合里的时候需要花费的代价呢? 答案是将一半的点反过来。 因为显然在 第三种情况中连边的两个点 x + y 的和的奇偶性肯定是不同的, 所以这就是一个二分图了, 那么我们只要把这个二分图中一般的点 完全反过来, 即使把源当成汇, 把汇当成源, 那么就是两点不在同一集合的时候要花费的代价啦!!

 

 【bzoj2127】happiness

一样最开始肯定要算出总的收益的, 然后总结一下每一种方案需要付出的代价:如果二人 同选 文, 就要付出两人选理的代价的和 + 同选理的代价; 二人一个选文一个选理, 就要付出 一人选理的代价 + 一人选文的代价 + 同选文的代价和 + 同选理的代价和。

思维的过程写不出来,,下面是copy的结论:

    对于原图中所有相邻的两个人A,B,我们建边:

    s->A:cost[A文]+c[文][A][B]/2,s->B:cost[B文]+c[文][A][B]/2;

    A->t:cost[A理]+c[理][A][B]/2,B->t:costB[理]+c[理][A][B]/2;

    A<-->B:c[文][A][B]/2+c[理][A][B]/2

    这样会出现两种割,分别对应两种相同,一种选文一种选理。

这道题还有很多其它的建图方法

zyb 看了一眼这道题然后 说这不是随便做, 怎么割一下都行吗.

唉我还是太弱。

 

 

bzoj 1797: [Ahoi2009]Mincut 最小割

在残留的途中, 如果一条边 (u, v) v 和 T 联通,说明存在一条, 如果 u 还和 S 联通, 说明必选这条。

上面那样做是不对哒。

我们想到如果 (u, v) 这条边是 可以是割的话,说明如果 u 分到S 中, v 分到 T中, 仍然可以求出最大流。

强制 u 在 S 中的方法 上面说过了, 就是 从 S  到 u 连一条 INF 的边。如果这之后还有增广路的话, 说明这条边可以被割掉。而还有增广路 当且仅当 u 到 v 是联通的, 所以只要判 两个点是否联通就可以啦。

 

 

bzoj 1391: [Ceoi2008]order

sb 题, 但是卡dinic 嘤嘤嘤

有人说加上当前弧优化就可以了。

当前弧优化就是你在增广的时候如果这条边已经满流了以后就不用再访问它了, 就把 cur 设为它就可以了。

到这里我用过了两个优化, 写出来就是这样的了:

f = dfs(edge[i].to, t, min(maxf - cnt, edge[i].f));
if(!f) dist[edge[i].to] = -1;
edge[i].f -= f; edge[i ^ 1].f += f;
if(edge[i].f) cur[now] = i;

 

 

bzoj 1532: [POI2005]Kos-Dicing

嗯,,不能再简单的最大流, 但是数据范围比较大, 把上面的优化加上之后就可以很轻松地过掉了, 可以比不加快上几十倍。

 

 

bzoj 2561: 最小生成树

想一遍最小生成树的构造过程。 如果 (u, v) 这条边不在最小生成树中, 当且仅当在比 (u, v) 这条边小的选出边集中的边可以使 u 和 v 联通。

所以说这道题我们需要确定两个条件: ① 只用 比 (u, v)小的边不能使u,v 联通。 ② 只用比 (u,v)大的边不能使u,v联通。

贪心? 在形如技术分享这样的图中显然是错的。

再一次明确要做的事情:

在一堆边里, 去掉最少的边, 使得两个点不联通。

于是最小割就出来了 (^_^)

但是复杂度看起来很恐怖,,如果我不是在最小割的分类里看到这道题肯定不敢往这里想的。 后来 zyb 证明说复杂度还是很靠谱的, 没法卡, 但我没有太明白。

 

bzoj 1324: Exca王者之剑

 这题 amber 的论文已经说的不能再清楚了。

再理一下思路:

只有偶数时间可以有收益, 因为奇数时间的时候一定会在上一步的偶数时间的时候被删掉。

继而可以证明, 相邻的两个点不可以同时选。

那么一个猜想就是是否只要是两个不相邻的点就可以同时选呢。

适当地构造后是可以的。

于是问题就是一个简单的 二分图的最大点权独立集了。

 

 

bzoj 1562: [NOI2009]变换序列

求一张二分图上字典序最小的最大匹配。 (这道题的题意我当时就是读不懂读了好久,,,)

如果从后往前去依次匹配的话, 每个点都选尽可能小的匹配, 匹配完了之后就是字典序最小的方案啦!

证明用归纳法感受一下就好了。 如果 后 n - i 点已经处理完了, 即当前单看后n - i个点是尽可能小的字典序了。 下面匹配第i 个点。 如果第 i 个点能匹配到的最小的之前没有用过, 那自然就选它了, 对后面的没有影响。 如果 这个点在之前被用过了, 我们在匹配的时候会找一条增广路, 如果可以找到, 把增广路上的边全部取反, 显然是一个最优的可行解, 如果找不到增广路, 就再去匹配次小的点……

 

平面图最小割算法

平面图就是指每一个边的交点处都是一个点的图。比如说一个网格就是一个平面图。< /span>

然后把平面图中的每一个封闭的面作为一个点, 这样原来图中的一条边把原来的平面分成两部分就代表连接了它分出来的那两个面。 所以新图中的边数还是和原图相等的。然后再把原图中的那个位于图的外面, 面积是INF的那个面拆成两个点分别作为 源 和汇, 感受一下会发现在这张新图中从 源 到汇 的任意一条路径都是原图中的一个割, 因此如果要求最小割 的话只要求一遍新图的最短路就好了! 太神奇了。

 

bzoj 2007: [Noi2010]海拔

有两点是一定的:

① 所有点的高度只会是 0 或 1   ② 所有的0节点联通, 所有的①节点联通。

又因为原图是一个网格所以用对偶图求一遍最小割就好了。

 

bzoj bzoj3158 千钧一发 && bzoj 3275: Number

(2a+1)^2+(2b+1)^2=2(2a^2+2b^2+2a+2b+1)

 

附 :

 我的 Dinic 模板

int n, m, head[MAXN], cur[MAXN], ee = -1, dist[MAXN], q[MAXN], ans;
struct Edge{int to, next, f;}edge[MAXM];
inline void addedge(int x, int y, int f){edge[++ ee].to = y; edge[ee].f = f; edge[ee].next = head[x]; head[x] = ee;}
inline void add(int x, int y){addedge(x, y, 1); addedge(y, x, 1);}
bool bfs(int s, int t){
for(int i = 1; i <= n; i ++)dist[i] = -1;
int tt = 0, w = 1;
dist[s] = 1; q[0] = s;
while(tt != w){
int u = q[tt ++];
for(int i = head[u]; i != -1; i = edge[i].next)if(dist[edge[i].to] == -1 && edge[i].f){
dist[edge[i].to] = dist[u] + 1;
if(edge[i].to == t)return 1;
q[w ++] = edge[i].to;
}
}return 0;
}
int dfs(int now, int t, int maxf){
int cnt = 0, f;
if(now == t)return maxf;
for(int i = cur[now]; i != -1; i = edge[i].next)if(dist[edge[i].to] == dist[now] + 1 && edge[i].f){
f = dfs(edge[i].to, t, min(maxf - cnt, edge[i].f));
edge[i].f -= f; edge[i ^ 1].f += f; cnt += f;
if(!f)dist[edge[i].to] = -1;
if(edge[i].f)cur[now] = i;
if(cnt == maxf)return cnt;
} return cnt;
}
void dinic(int s, int t){while(bfs(s, t)){ for(int i = 1; i <= n; i ++)cur[i] = head[i]; ans += dfs(s, t, INF);}}

 

UPD:

算是网络流相关的吧:

最小链覆盖 = 最长反链 = 极大(小)元素个数。

网络流小结

标签:

原文地址:http://www.cnblogs.com/lixintong911/p/4860762.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!