二分图&网络流初步
链接 : 最小割&网络流应用
EK太低级了,不用。 那么请看:#6068. 「2017 山东一轮集训 Day4」棋盘,不用EK你试试?
dinic模板及部分变形应用见zzz大佬的博客:网络流学习笔记(反正我的码风和大佬zzz的差不多)
二分图覆盖与匹配
最小点覆盖=最大权匹配
简单(假)证明:
最小点覆盖包含的点数不可能小于最大匹配包含的边数。
尝试增广,把dfs到的点标记,那么左部未被标记的点和右部被标记的点为合法点。
求最小点覆盖的方案:详见 题解 UVA11419 【SAM I AM】
将用到的x和y点打上标记flag。(因为最小点覆盖的点一定连有满流的边)
在余量网络里dfs,将途径的点打上标记arr。
选择的方案(之一)为:所有打flag标记的点中:打了arr标记的x点和没打arr标记的y点(为了防记重)。
(紫圈是打了标记的点(还落掉了左上角的那个点))
习题
二分图最大独立集 = n(二分图总点数) - 最大匹配
证明:去掉二分图的最小点覆盖。
二分图的最小点权覆盖和最大点权独立集
不让每个点连向源汇的边容量为1,而让其为点权。跑最大流为最小点覆盖。跑最大流即为最小点权覆盖, \(n - maxflow\) 即为最大点权独立集。
不愿意证明,感性理解一下吧。
习题
DAG的最小路径覆盖(=最小路径点覆盖)
给个DAG,要求用尽量少的路径(可以相交)(路径可以起点等于终点)覆盖所有点。
把起点集合看作左部图,终点集合看作右部图,起点向终点连边,右部图的点 \(cur\) 向左部图的点 \(cur\) 连反向边。那么 DAG总点数 \(n\) - 在二分图上跑出来的最大流 \(flow\) = 最小路径覆盖。
简单(假)证明:
一开始不跑最大流时,相当于尚且没有选路径,“最小”路径覆盖为 \(n\)。跑最大流,每找到一条增广路,就相当于找到一条边,连接了两个点,“最小”路径覆盖减去1.所以最终 \(n\) - \(flow\) 即为最小路径覆盖。
较为严谨的一个证明
每条路径中点最多入一出一,如果度数还要多,就要“新建”一条路径了。
首先让路径都初始化成 \(n\) 条长度为0的路径。然后要求尽可能多得合并路径。
每次选择一条边,就相当于将两个点的“路径”合并成为一条路径。当然,如果发现那一个点已经被合并了,那么可以跳过那个点,再从那个点的一条出边继续寻找合并的路径;或者“换掉”那一个点,即反悔操作。
找方案
模拟上面的证明。枚举左部图所有点 \(u\),如果他的一条正向出边 \((u~ -> v)\) 满流,说明选择了这条边,这条边在最小路径覆盖的边集中。
拓展
即便要求路径长度不可以为1,只要没有度数为0的点,那么这么求的答案仍然正确。(毕竟0路径是最差的路径,可以通过硬给它塞成一个1路径,而答案不会更劣)求方案也可以随便给0点找一条出边或入边。
但是如果要求路径不交,那可能就要拓扑DP之类的了。
习题
升级版:最小可重路径点覆盖
给个DAG,要求用尽量少的路径(可以相交,且相交部分可以不止一个点)覆盖所有点。
(模仿李煜东书)如果 \(u~->~p~->~v\) 且 \(x~->p~->y\),那么我们把 \(x\) 和 \(y\) 直接连一块,再按照普通的最小路径点覆盖做即可。
进一步地,我们索性全部把间接相连的点对直接连一块,那么整道题就可以像普通最小路径点覆盖那样做了。这部分可以用 \(Floyd\) 思想实现
似乎这种方法叫做传递闭包
Code:
//v[i][j]:邻接矩阵
for (register int i = 1; i <= n; ++i) v[i][i] = true;
for (register int k = 1; k <= n; ++k)
for (register int i = 1; i <= n; ++i)
for (register int j = 1; j <= n; ++j)
v[i][j] |= v[i][k] && v[k][j];
for (register int i = 1; i <= n; ++i) v[i][i] = false;
习题
DAG 的不可重叠最小路径边覆盖
给一张 DAG,选择一些路径,使得这些路径能够遍历到所有边,且每条边恰好被遍历到了一次。
做法
(考虑将入边和出边拼路径)
\]
DAG 的可重叠最小路径边覆盖
支持一种操作:选择一条路径,让其起点的 out++,终点的 in++。然后求出不可重叠最小路径边覆盖(加一串重边)
据lyd大佬的课件,“我们根据以往的经验知道,网络流寻找路径的问题,应当把每个点拆点,然后把路径拆成若干条边、以及拆点之后两个同点之间的边。”
然而我还是太年轻了,实在理解不了啊。(事实上最小路径点覆盖我都无法理解)。于是转而成为背诵内容。
• 把每个点拆成左、右两个,右点向左点连容量为+∞的边。
• 从源点S向所有in[i]>out[i]的左点连边,容量为 in[i]-out[i]。
• 从所有in[i]<out[i]的右点向汇点T连边,容量为 out[i]-in[i]。
• 对于原图中的边(u,v),从u的左点向v的右点连容量为+∞的边。
• 求最大流,那么答案就是满流减去最大流。
• 一条边上有多少流量,就要添加多少条重边,然后dfs输出方案。
注释:第四点中的“满流”指的是 \(S\) 点连向的容量之和。
事实上,可重最小路径边覆盖还有一种最小流(全称:有源汇有上下界最小流)的做法:建立一个虚拟源点 \(S\) 向所有点连 \([0,\infty)\) 的边,表示可以从任意点开始;所有点向一个虚拟汇点连 \([0,\infty)\) 的边,表示可以从任意点结束;原图中的边的上下界为 \([1,\infty)\),表示至少经过一次。然后跑有源汇有上下界最小流,最小流即为答案。
“三分图”模型
(其实或许根本没有“三分图”这个名字)
如果我们的问题是对于一些点,其中每一个点 \(i\) 必须和集合 \(S_i\) 中的一个点匹配,同时必须和集合 \(T_i\) 中的一些点匹配,并且这些点的 \(S\) 和 \(T\) 集合互不交叉,且这些点不属于 \(S,T\) 中的任何一个集合,那么我们可以用“三分图”模型来解决。
左边一列点 \(S\),右边一列点 \(T\),中间一列点 \(i\),中间向两边匹配跑(最小费用)最大流即可。
例题:P1231 教辅的组成 ;P4142 洞穴遇险 ;bzoj 1711 Dining 吃饭
最大流
最大流的必须边:
满流 并且 在残量网络上属于不同的SCC(强连通分量)(为了排除非必须边的可行边)。
最大流的可行边:
满流 或 在残量网络上属于不同的SCC。
例题:380. 舞动的夜晚
一条显然的性质 : 最大流的边是具有可加性的。
如 建立 \((u, v, val1)\) 和 \((u, v, val2)\) 就相当于建立 \((u, v, val1 + val2)\)
最小割
最大流等于最小割。
如何找到最小割的割边?
从S开始沿着残量网络BFS,把能到达的点标记上。
连接已标记的点和未标记的点的正向边为该网络的一个最小割集。(-by lyd大佬)
如何找最小割的必须边?
从S开始BFS跑残量网络。
从T开始反向BFS跑残量网络。
枚举从S指向T的满流边,这些边即为必须边
如何找某种情况的最小割的可行边?
满流
删掉后找不到u -> v的路径
于是:残余网络中tarjan跑SCC, (u, v)的u, v都在同一SCC中说明存在残量网络u -> v的路径 -by lyd大佬
习题
网络流常用思想:点边转化思想
拆点:
把点拆成入点和出点,两点间边权为点权。或者拆成有两个特殊含义的点。
例题:
Cable TV Network
Kaka's Matrix Travels
P1251 餐巾计划问题
拆边:
对于边权比较复杂的问题(比如和第几种情况、之前选用该点次数等有关,但不管怎样都会选最小的情况作为代价),把所有情况分解成某几条边上的权值和。(类似于二进制拆分多重背包?)
如: #6068. 「2017 山东一轮集训 Day4」棋盘 ;还有P4307 [JSOI2009]球队收益 / 球队预算
一些毒瘤题
P6185 [NOI Online 提高组]序列(民间数据)
题意: 给一个长度为 \(n\) 的序列 \(a\)。并且给 \(m\) 种操作:\(t, u, v\),\(t=1\)表示 \(u, v\) 可以同时加或减一个数; \(t = 2\) 表示 \(u, v\) 可以一个加上个数,另一个减去相同的数。询问能否将 \(a\) 全部变成0.
数据规模:n <= 1e5。存在 t 全部为 1 和全部为 2 的数据。
根据套路想法,我们不难发现, \(t = 2\) 时不改变两数之和, \(t = 2\) 时不改变两数之差。如果 \(t_i = 2(1 <= i <= m)\),那么我们将 \(u_i, v_i\) 连边,如果所有连通块的权值都为0,那么有解,否则无解。
现在又加上 \(t = 1\),发现 \(u, v\) 之差是不改变的,但是这并不好办(毕竟不是相邻的差)。但是,如果学过“混合图欧拉回路”的网络流解法,我们应该能发现这种操作也是具有一定的传递性的,并且是隔项传递的。这有点像二分图,因此二分图解法是本题的解法之一。一种简便的方法:
我们把隔两条边的点合并成为一个连通块,连通块内的值就可以在保证总和不变的前提下随意改变了。这种方法的实质其实是将奇环合并,将二分图的左右部图(联通的)合并成为一点。最终会剩下一些度数不超过1的点。此时模拟题意,对于一条边\((u, v)\),要求 \(val[u] = val[v]\);对于边 \((u, u)\),要求 \(u\) 的值为偶数。对于度数为 0 的点,要求其值为0.
比较考验代码能力,毕竟要进行那么多种合并。不过也没有那么毒。(不明白为什么考试时连60分都没拿到)
注意!
- 最大独立集 \(= n - mxflow\), 最小点覆盖 \(=\) 最大匹配 \(=\) 最大流,最小路径点覆盖 \(=\) \(n\) \(-\) 拆点后最大流
搞不清最好随便搞几个二分图画一画。
dinic的弧优化记得加,记得初始化!!别忘了s、t的初始化!!+1
dep/dis要初始化为0x3f,不要初始化为0!!!
ecnt 初始化为1,不是0!!!
一定要连反向边!!!!!
不要随便连边!!!注意边的方向!!!格外警惕
addedge(t, i, inf)
这样的连边!!!费用流注意一下 \(vis\) 的使用情况
费用流注意 SPFA 的队列要开30倍左右(大概是
<< 6
;<< 5
也可以,但是要是写成<< 30
就不好了)
附
模板(调试用)
最大流
int que[NNN << 1], front, rear;
int dep[NN];
inline bool bfs() {
memset(dep, 0x3f, sizeof(dep));
front = rear = 0;
for (register int i = 1; i <= ptot; ++i) hcur[i] = head[i];
for (register int i = N - 1; i <= N + ptot; ++i) hcur[i] = head[i];
dep[s] = 0; que[++rear] = s;
while (front < rear) {
int cur = que[++front];
for (register int i = head[cur]; i; i = e[i].nxt) {
int to = e[i].to;
if (dep[to] <= inf || !e[i].val) continue;
dep[to] = dep[cur] + 1;
que[++rear] = to;
}
}
return dep[t] <= inf;
}
int dfs(int cur, int limi) {
if (cur == t || !limi) return limi;
int tmp, flow = 0, to;
for (register int i = hcur[cur]; i; i = e[i].nxt) {
to = e[i].to; hcur[cur] = i;
if (dep[to] != dep[cur] + 1) continue;
tmp = dfs(to, min(limi, e[i].val));
if (!tmp) continue;
e[i].val -= tmp;
e[i ^ 1].val += tmp;
flow += tmp;
limi -= tmp;
if (!limi) break;
}
return flow;
}
int main() {
...
while (bfs()) {
mxflow += dfs(s, inf);
}
...
}
最小费用最大流
inline bool spfa() {
memset(dis, 0x3f, sizeof(dis));
front = rear = 0;
for (register int i = 1; i <= ptot; ++i) hcur[i] = head[i];
dis[s] = 0; que[++rear] = s; vis[s] = true;
while (front < rear) {
int cur = que[++front]; vis[cur] = false;
for (register int i = head[cur]; i; i = e[i].nxt) {
int to = e[i].to;
if (dis[to] <= dis[cur] + e[i].fare || !e[i].val) continue;
dis[to] = dis[cur] + e[i].fare;
if (!vis[to]) que[++rear] = to, vis[to] = true;
}
}
return dis[t] < inf;
}
int dfs(int cur, int limi) {
if (cur == t || !limi) return limi;
vis[cur] = true;
int flow = 0, tmp, to;
for (register int i = hcur[cur]; i; i = e[i].nxt) {
to = e[i].to; hcur[cur] = i;
if (dis[to] != dis[cur] + e[i].fare || vis[to]) continue;
tmp = dfs(to, min(limi, e[i].val));
if (!tmp) continue;
flow += tmp;
limi -= tmp;
e[i].val -= tmp;
e[i ^ 1].val += tmp;
if (!limi) break;
}
vis[cur] = false;
return flow;
}
int main() {
...
int res = 0;
ll ans = 0;
while (spfa()) {
res = dfs(s, inf);
ans += dis[t] * res;
}
...
}
二分图&网络流初步的更多相关文章
- 二分图&网络流&最小割等问题的总结
二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...
- hdu1569-方格取数-二分图网络流
方格取数(2) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- 【洛谷】4304:[TJOI2013]攻击装置【最大点独立集】【二分图】2172: [国家集训队]部落战争【二分图/网络流】【最小路径覆盖】
P4304 [TJOI2013]攻击装置 题目描述 给定一个01矩阵,其中你可以在0的位置放置攻击装置. 每一个攻击装置(x,y)都可以按照“日”字攻击其周围的8个位置(x-1,y-2),(x-2,y ...
- 「SDFZ听课笔记」二分图&&网络流
二分图? 不存在奇环(长度为奇数的环)的图 节点能黑白染色,使得不存在同色图相连的图 这两个定义是等价哒. 直观而言,就是这样的图: 二分图有一些神奇的性质,让一些在一般图上复杂度飞天的问题可以在正常 ...
- 洛谷 P2756 飞行员配对方案问题 (二分图/网络流,最佳匹配方案)
P2756 飞行员配对方案问题 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其 ...
- [bzoj3158]千钧一发——二分图+网络流
题目 传送门 题解 很容易建立模型,如果两个点不能匹配,那么连一条边,那么问题就转化为了求一个图上的最大点权独立集. 而我们可以知道: 最大点权独立集+最小点权覆盖集=总权值. 同时最小点权覆盖在一般 ...
- 网络流初步——增广路算法(EK)模板
#include <iostream> #include <queue> #include<string.h> using namespace std; #defi ...
- 网络流初步:<最大流>——核心(增广路算法)(模板)
增广路的核心就是引入了反向边,使在进行道路探索选择的时候增加了类似于退路的东西[有一点dp的味道??] 具体操作就是:1.首先使用结构体以及数组链表next[ MAXN ]进行边信息的存储 2.[核心 ...
- 0x6A 网络流初步
CH Round #17-C 这个算是一个技能点吧,不点不会,点了就没什么了.懒得写看书吧书上的1应该是0... 我又回来了太懒了不想翻书还是写写吧 必须边的判定条件:该边流量为0且两端的点在残余网络 ...
随机推荐
- 如果人生也能存档——C#中的备忘录模式
大家好,老胡又和大家见面了.首先承认今天的博客有点标题党了,人生是没有存档,也没有后悔药的.有存档和后悔药的,那是游戏,不知道这是不是游戏让人格外放松的原因之一. 今天恰逢端午放假,就让我们来试着做一 ...
- CentOS 7 安装VNC
VNC需要系统安装的有桌面,可以进行下面操作安装GNOME 桌面. #列出的组列表里有GNOME Desktopyum grouplist | grep GNOME 安装 yum groupinsta ...
- python计算矩阵均匀分布程度
计算N×M(建议维度大于100*100)的0,1矩阵均匀分布程度,值由0到1表示不均匀到均匀 import numpy as np def make_rand_matrix(side=20): # 制 ...
- 浅谈MySQL多表操作
字段操作 create table tf1( id int primary key auto_increment, x int, y int ); # 修改 alter table tf1 modif ...
- CSS选择器整理以及优先级介绍
一.基础选择器 选择器 名称 描述 兼容性 * 通配选择器 选择所有的元素 ie6+ E 元素选择器 选择指定的元素 ie6+ #idName id选择器 选择id属性等于idName的元素 ie6+ ...
- vim常用指令参考
(完)
- 利用搭载好的工控机环境跑yolov3-tiny
辛辛苦苦搭载好GPU环境现在要开始测试下效果 1,准备好数据集 2,测试开始 (1),如果尚未安装Darknet,则应先进行安装 git clone https://github.com/pjredd ...
- 【Oracle】arraysize的研究(存在疑问)
arraysize的研究(存在疑问) SYS@proc> create table aaa (id1 int,id2 int,id3 int,id4 int); Table created. S ...
- (私人收藏)[开发必备]HTML5最全快速查找离线手册(可查询可学习,带实例)
[开发必备]HTML5最全快速查找离线手册(可查询可学习,带实例) HTML5最全快速查找离线手册:https://pan.baidu.com/s/19seE8TJQSx4IsWgXtKQS0Aj9y ...
- 主流App自动化测试框架对比
1.主流App自动化测试框架对比 2.Appium自动化测试框架 官方网址:http://appium.io/ 跨架构:支持原生.混合以及web移动应用 跨平台:Android & I ...