Day4 网络流与二分图

这篇具有很好参考价值的文章主要介绍了Day4 网络流与二分图。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

之前那篇博客是在入门网络流时写的,现在对网络流重新有了一定的理解。

学习笔记

1. 最大流

【模板】最大流

FF 增广思想

Ford–Fulkerson 增广,核心即不断找增广路并增广。

dfs 实现

// dfs : 流入 u 的流量为 sum, 求流出的最大流
int dfs(int u, int sum) 
{
	if(sum == 0 or u == t) return sum;
	
	vis[u] = true;
	
	int flow = 0;
	for(int v = 1; v <= n; v++)
	{
		if(!vis[v] and r[u][v] > 0)
		{
			//找 u 到 t 路上的最小限制并增广
			int delta = dfs(v, min(sum, r[u][v]));
			r[u][v] -= d, r[v][u] += d;
			flow += delta, sum -= delta;
		}
	}
	return flow;
}

FF brute code

这种方法的复杂度与最大流 f f f 有关,至多执行 f f f 轮 dfs,时间复杂度 O ( n f ) O(nf) O(nf)

bfs 实现 / EK

FF 增广的 bfs 实现也称 EK 算法。

// bfs 寻找增广路
bool bfs()
{
	memset(d, 0, sizeof(d)); memset(pre, 0, sizeof(pre));
	
	d[s] = 1, q.push(s); 
	
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		for(int v = 1; v <= n; v ++)
			if(d[v] == 0 and r[u][v] > 0)
				pre[v] = u, d[v] = d[u] + 1, q.push(v);
	}
	
	return d[t];
}
// 找到增广路后增广
int augment()
{
	int flow = 1e9;
	for(int a=t; a!=s; a=pre[a]) flow = min(flow, r[pre[a]][a]);
	for(int a=t; a!=s; a=pre[a]) r[pre[a]][a] -= flow, r[a][pre[a]] += flow;
	return flow;
}

FF EK code

EK 算法的时间复杂度是 O ( n m 2 ) O(nm^2) O(nm2)

证明:每条边至多做 n 2 \dfrac n 2 2n 次增广路上的关键边。
OI-wiki

Dinic

通过 bfs 找增广路并对图分层标记,每次 dfs 只访问下一层的结点。

同时加上当前弧优化,即不重复访问增广到极限的边,维护第一条有必要尝试的边。
有必要这样做的原因是如果一个节点有大量出边与入边,挨个遍历可能会 O ( ∣ E ∣ 2 ) O(|E|^2) O(E2)
可以这样做的原因是因为每一遍增广过程中,遍历出边的顺序都是一样的。

注意在流入 u u u 的流量为 0 0 0 时要退出,否则会导致当前弧优化的出错。

时间复杂度 O ( n 2 m ) O(n^2m) O(n2m)

bool bfs()
{
	memset(d, 0, sizeof(d)); 
	d[s] = 1, q.push(s); 
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		for(int i=head[u]; i; i=e[i].nxt)
		{
			int v = e[i].to;
			if(d[v] == 0 and e[i].r > 0)
				d[v] = d[u] + 1, q.push(v);
		}
	}
	return d[t];
}
int dfs(int u, int sum) // dfs 流入 u 的流量为 sum
{
	if(sum == 0 or u == t) return sum;
	
	int flow = 0;
	
	for(int i=cur[u]; i; i=e[i].nxt) 
	{
		cur[u] = i; // 当前弧优化
		int v = e[i].to;
		if(d[v] == d[u] + 1 and e[i].r > 0)
		{
			int d = dfs(v, min(sum, e[i].r));
			e[i].r -= d, e[i ^ 1].r += d;
			flow += d, sum -= d;
		}
	}
	
	return flow;
}

Dinic code

2. 二分图最大匹配

飞行员配对方案问题

  • 二分图:对于 G ( V , E ) G(V,E) G(V,E),分成两个点集 V 1 , V 2 V1,V2 V1,V2 ,对于所有的 ( u , v ) ∈ E (u,v) \in E (u,v)E, 保证 u , v u,v u,v 属于不同点集。

    容易发现二分图中不存在奇环。(走偶数步才能回到某一点集)

  • 二分图的匹配:选定一些边,这些边之间没有公共点。

建网络流模型即可,通过虚拟源点和虚拟汇点限制 1 1 1

如果要输出方案,可以通过 f ( u , v ) < c ( u , v ) f(u,v) < c(u,v) f(u,v)<c(u,v)判断。如果根据残量网络,需要根据反向边的残量网络判断。

代码

3. 最大权闭合子图

分成正点和负点,把不选正点看作损失,每一种割对应一种方案代表不选。

答案即为正收益减去最小损失,即最小割,根据最小割最大流,即最大流。

具体可以看我之前的博客 浅谈网络流。

4. 费用流

【模板】最小费用最大流

既然是最大流的前提上费用最小费用,用到的思想一定是基于 FF 增广思想上的。

SSP 算法

贪心,在每次增广中贪心的选择单位流量花费最小的增广路增广。考虑到负权,使用 SPFA 实现。

原图有负环时,最小费用不存在。若无负环,则图中不可能存在负环。

原因:考虑归纳法。

如果当前残量网络上无负环,则增广后同样无负环。若负环由原图上正环的反向边组成,由于找的是最短路,不可能经过原图上正环的所有边;若负环由一部分正向边一部分反向边组成,先遍历的一定是相对较短的,则形成的环非负。

时间复杂度 O ( n m f ) O(nmf) O(nmf) f f f 为最大流。

基于 EK 的实现代码

基于 Dinic 的实现代码

5. 上下界网络流

无源汇有上下界可行流

无源汇有上下界可行流

是否存在一种可行流使得每个点都满足流量平衡,对于边 ( u , v ) (u,v) (u,v),有限制 l ( u , v ) ≤ f ( u , v ) ≤ r ( u , v ) l(u,v) \le f(u,v) \le r(u,v) l(u,v)f(u,v)r(u,v)

设计 f ′ ( u , v ) = f ( u , v ) − l ( u , v ) f'(u,v)=f(u,v)-l(u,v) f(u,v)=f(u,v)l(u,v) 0 ≤ f ′ ( u , v ) ≤ r ( u , v ) − l ( u , v ) 0 \le f'(u,v) \le r(u,v) - l(u,v) 0f(u,v)r(u,v)l(u,v),即一般的网络流模型。

此时 f ′ f' f 关于点 u u u 并不满足流量平衡。

根据 f f f 的流量平衡可推出 f ′ f' f 应该满足 ∑ x → u l ( x , u ) + ∑ x → u f ′ ( x , u ) = ∑ u → y l ( u , y ) + ∑ u → y f ′ ( u , y ) \sum_{x \to u} l(x,u)+\sum_{x \to u} f'(x,u) = \sum_{u \to y} l(u,y)+\sum_{u \to y} f'(u,y) xul(x,u)+xuf(x,u)=uyl(u,y)+uyf(u,y)

记虚拟源点为 s s s,虚拟汇点为 t t t,建 s s s u u u 容量为 ∑ x → u l ( x , u ) \sum_{x \to u} l(x,u) xul(x,u) 的边,建 u u u t t t 容量为 ∑ u → y l ( u , y ) \sum_{u \to y} l(u,y) uyl(u,y) 的边。

跑最大流,有解当且仅当 ∑ f ( s , u ) = ∑ u ( ∑ x → u l ( x , u ) ) \sum f(s,u) = \sum_u (\sum_{x \to u} l(x,u)) f(s,u)=u(xul(x,u))。相当于问存不存在一种方案, f ( s , u ) f(s,u) f(s,u) 都能达到容量限制,此时一定是最大流。如果最大流不能满足,那么一定无解.

求方案根据 f ′ f' f f f f 即可。

代码

有源汇有上下界可行流

有源汇时,考虑到只有源点与汇点不满足流量平衡,由汇点向源点连一条 [ 0 , inf ⁡ ] [0,\inf] [0,inf] 的边,转为无源汇上下界可行流。

有源汇有上下界最大流

有源汇有上下界最大流

SOL1:二分最大流 f f f,由汇点向源点连一条 [ f , inf ⁡ ] [f,\inf] [f,inf] 的边,转为无源汇上下界可行流,时间复杂度 O ( n 2 m log ⁡ V ) O(n^2m \log V) O(n2mlogV)

SOL2:找到一条可行流,在可行流的残量网络上跑 S S S T T T 的最大流,两者相加。


题目

清理雪道

DAG 上的最小边覆盖问题。

本题题解

CF1783F Double Sort II

错排建图的套路。

先只考虑一个数列:记 i i i 所在位置 p i p_i pi,将 i → p i i \to p_i ipi 建边,形成若干个环,每次操作可以让环上少一个点,因此最小操作次数为 n n n 减去环的数量。

如果从反面出发,想最多能保留几个点可以不动,省操作次数,能保留的数量就是环的数量。

考虑两个数列:对于一个环,最多被省一个点。对于一个点,最多被省一次。

i i i 所在的两个环建边跑二分图最大匹配即可。

CF1766F MCF

最小费用有源汇可行流,但有一个流量与容量奇偶性相同的限制。

对于奇数边有下界 f ( u , v ) ≥ 1 f(u,v) \ge 1 f(u,v)1,给他们制定下界,先让他们流入 1 1 1 的容量。然后我们令 f ′ ( u , v ) = f ( u , v ) 2 , c ′ ( u , v ) = c ( u , v ) 2 f'(u,v) = \dfrac {f(u,v)} {2},c'(u,v) =\dfrac {c(u,v)} {2} f(u,v)=2f(u,v)c(u,v)=2c(u,v)文章来源地址https://www.toymoban.com/news/detail-595867.html

到了这里,关于Day4 网络流与二分图的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序Day4笔记

    1. 组件的创建与引用 创建组件 在项目的根目录中,鼠标右键,创建components - test文件夹 在新建的test文件夹上,鼠标右键,点击新建Component 键入组件的名称之后回车,会自动生成组件对应的4个文件,后缀名分别为.js, .json, .wxml, .wxss 引用组件 局部引用:组件只能在当前被引用

    2024年02月09日
    浏览(34)
  • c++学习(day4)

    友元是一种定义在类外部的普通函数或类 1.1 全局函数作为友元函数 声明一个全局函数作为类的友元函数,则允许该全局函数,访问类中各个权限下的成员 在类中要将该函数进行声明:friend 全局函数头; 1.2 类的成员函数作为友元函数(了解) 声明一个其他类的成员函数作

    2023年04月23日
    浏览(31)
  • 微服务学习Day4

    2024年02月19日
    浏览(33)
  • 网络渗透day4-Windows域

    针对于Windows系列服务器的最新版本 server2022操作系统的域环境的搭建与维护,做为网络安全其中一项分支“内网渗透”,域是不可绕过的底层基础,本模块重点讲解域环境之外还讲解加密与证书技术,了解PKI相关的应用,最后带入目前常用的攻击语言操作powershell,用它替代

    2024年02月11日
    浏览(28)
  • 前端学习——ajax (Day4)

    Promise - 链式调用

    2024年02月16日
    浏览(35)
  • 前端学习——JS进阶 (Day4)

    练习 throw 抛异常 try/catch 捕获错误信息 debugger this指向——普通函数 改变this 节流 案例 防抖

    2024年02月16日
    浏览(42)
  • C# 学习笔记2-控制流与类型转换

    关于变量的简单操作 判断 循环 类型转换 异常处理 检查数字类型的溢出 一元运算符 Unary operators x++ , ++x , x-- , --x 。 这些运算符同 C++。 postfix operator 后置运算符 还有 typeof(int) , sizeof(int) 。 二元运算符 Binary arithmetic operators 无非是: + 、 - 、 * 、 / 、 % modulus 模 remaind

    2024年02月02日
    浏览(38)
  • day4 驱动开发 c语言学习

    不利用系统提供的register_chrdev,自己实现字符设备的注册 底层代码 led.c 应用层代码 app.c 头文件 head.h

    2024年02月14日
    浏览(39)
  • 【Node.js学习 day4——模块化】

    什么是模块化与模块? 将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 模块化 其中拆分的 每个文件就是一个模块 ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用。 什么是模块化项目? 编码时是按照模块一个一个编码的

    2024年01月16日
    浏览(49)
  • 数据结构与算法学习(day4)——解决实际问题

    在本章的学习此前,需要复习前三章的内容,每个算法都动手敲一遍解题。宁愿学慢一点,也要对每个算法掌握基本的理解! 前面我们学习了简化版桶排序、冒泡排序和快速排序三种算法,今天我们来实践一下前面的三种算法。 本章的学习目标: (1)回顾三个算法的基本原

    2024年02月09日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包