Day4 网络流与二分图

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

1. 最大流

FF 增广思想

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

dfs 实现

// FF brute
#include <bits/stdc++.h>
#define int long longusing namespace std;int n, m, s, t, r[205][205], ans;bool vis[205];
int dfs(int u, int sum) // sum:流入 u 的流量
{if(sum == 0 or u == t) return sum;vis[u] = true;int flow = 0;for(int i=1; i<=n; i++){if(!vis[i] and r[u][i] > 0){//找 u 到 t 路上的最小限制并增广int d = dfs(i, min(sum, r[u][i]));r[u][i] -= d, r[i][u] += d;flow += d, sum -= d;}}return flow;
}signed main()
{cin >> n >> m >> s >> t;for(int i=1; i<=m; i++){int u, v, w;cin >> u >> v >> w;r[u][v] += w;}int d;while(d = dfs(s, 1e9)) {memset(vis, 0, sizeof(vis));ans += d;}cout << ans;
}

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

bfs 实现 / EK

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

// FF EK#include <bits/stdc++.h>
#define int long longusing namespace std;int n, m, s, t, r[205][205], ans, d[205], pre[205];
queue <int> q;
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 i=1; i<=n; i++)if(d[i] == 0 and r[u][i] > 0)pre[i] = u, d[i] = d[u] + 1, q.push(i);}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;
}signed main()
{cin >> n >> m >> s >> t;for(int i=1; i<=m; i++){int u, v, w;cin >> u >> v >> w;r[u][v] += w;}while(bfs()) ans += augment();cout << ans;
}

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

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

Dinic

通过 bfs 对图分层标记,每次 dfs 只访问下一层的结点。
同时加上当前弧优化,即不重复访问满流边,维护第一条有必要尝试的边。

// dinic#include <bits/stdc++.h>
#define int long longusing namespace std;struct Edge{int nxt, to, r;
}e[10005];int tot = 1, head[205];
void add_edge(int u, int v, int w)
{e[++tot] = {head[u], v, w};head[u] = tot;
}int n, m, s, t, ans, d[205], cur[205];queue <int> q;
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)
{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;
}signed main()
{cin >> n >> m >> s >> t;for(int i=1; i<=m; i++){int u, v, w;cin >> u >> v >> w;add_edge(u, v, w);add_edge(v, u, 0);}while(bfs()) {for(int i=1; i<=n; i++) cur[i] = head[i];ans += dfs(s, 1e9);}cout << ans;
}

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)判断。如果根据残量网络,需要根据反向边的残量网络判断。

#include <bits/stdc++.h>
using namespace std;int n, m, s, t, r[105][105], ans, d[105], cur[105];
queue <int> q;
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=1; i<=n+2; i++)if(d[i] == 0 and r[u][i] > 0)d[i] = d[u] + 1, q.push(i);}return d[t];
}int dfs(int u, int sum)
{if(sum == 0 or u == t) return sum;int flow = 0;for(int v=cur[u]; v<=n+2; v++){cur[u] = v;if(d[v] == d[u] + 1 and r[u][v] > 0){int d = dfs(v, min(sum, r[u][v]));r[u][v] -= d, r[v][u] += d;flow += d, sum -= d;}}return flow;
}int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> m >> n;s = n+1, t = n+2;while(1){int u, v;cin >> u >> v;if(u == -1 and v == -1) break;r[u][v] = 1;}for(int i=1; i<=m; i++) r[s][i] = 1;for(int i=m+1; i<=n; i++) r[i][t] = 1;while(bfs()) {for(int i=1; i<=n+2; i++) cur[i] = 1;ans += dfs(s, 1e9);}cout << ans << "\n";for(int u=1; u<=m; u++){for(int v=m+1; v<=n; v++){if(r[v][u]) cout << u << " " << v << "\n";}}	return 0;
}

3. 最大权闭合子图

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

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

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


A. 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 所在的两个环建边跑二分图最大匹配即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/3844.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OkHttp原理和机制讲解

OkHttp原理和机制讲解 本文链接&#xff1a;https://blog.csdn.net/feather_wch/article/details/131767285 1、OkHttp的原理和机制包括哪些部分&#xff1f; 设计模式的运用&#xff1a;建造者模式、外观模式、责任链模式整体流程分发器(调度机制)TCP链接复用(复用机制)拦截…

2023米哈游图像算法暑期实习面经

来源&#xff1a;投稿 作者&#xff1a;LSC 编辑&#xff1a;学姐 本文不可转载 违者必究 1.自我介绍 2.能实习多久&#xff1f;公司在心目中的地位排序等 3.是否了解公司&#xff0c;用他们的产品吗&#xff1f;(比如原神) &#xff0c;喜欢游戏吗&#xff1f; 我只知道公司…

划片机的作用将晶圆分割成独立的芯片

划片机是将晶圆分割成独立芯片的关键设备之一。在半导体制造过程中&#xff0c;晶圆划片机用于将整个晶圆切割成单个的芯片&#xff0c;这个过程被称为“晶圆分割”或“晶圆切割”。 晶圆划片机通常采用精密的机械传动系统、高精度的切割刀具和先进的控制系统&#xff0c;以确保…

web-其他注入

堆叠注入 mysqli_query()只能执行一条SQL语句&#xff0c;mysqli_multi_query()可以执行多条语句 堆叠注入与联合查询的区别&#xff1a;union 执行的语句类型是有限的&#xff0c;只能执行 select &#xff0c;堆叠注入可以执行任意语句。但使用堆叠注入&#xff0c;需要后端…

恢复idea删除的git本地文件

idea中删除git本地文件无法远程拉取pull已删除文件的问题 当前本地库处于另一个分支中&#xff0c;需将本分支Head重置&#xff0c;git 强行pull并覆盖本地文件 解决方式一&#xff1a; git fetch --all git reset --hard origin/master git pull解决方式二&#xff1a; git…

Oracle密码文件

Oracle密码文件 Oracle密码文件用于用户远程管理数据库验证 我们可以通过将普通用户加入到密码文件中&#xff0c;使他们可以使用sysdba或sysoper的权限来管理数据库 使用ORAPWD命令创建 语法如下: ORAPWD FILEfilename [ENTRIESnumusers] [FORCE{Y|N}] [IGNORECASE{Y|N}] …

ylb-项目简介

1、各模块服务功能 注&#xff1a;其部分实体类、接口、mapper文件由MyBatis逆向工程生成。 2、Maven管理&#xff08;多模块&#xff0c;继承和聚合&#xff09; 2.1 parent模块 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"…

DevOps系列文章之 Dockerfile 使用流程

制作项目应用镜像 主要步骤&#xff1a; Step1、准备项目应用程序包 Step2、编写Dockerfile及启动脚本 Step3、docker build 构建镜像 Step4、docker run 启动容器 Step5、docker exec 进入容器进行验证 Step6、镜像的导入导出 Step7、提交容器生成新镜像 Step1、准备项目应…

如何缩短 js 解析时间,如何优化首屏(延迟加载)

缩短js解析时间 代码优化 避免全局查找&#xff08;沿着作用域链找需要时间&#xff09;&#xff0c;避免闭包&#xff0c;用数据结构等 减小js的大小&#xff1a;压缩和混淆 压缩 剔除没用到的代码&#xff0c;把长表达式转换成同含义的短表达式等 语法转换和优化&#…

c++ 无锁队列的简单实现

无锁队列的基本介绍 一个关于无锁队列的多线程读写代码示例。在这里&#xff0c;我提供一个简单的示例来说明这个问题。 在使用无锁队列时&#xff0c;需要注意以下几点&#xff1a; 使用原子操作来实现对队列的读写操作&#xff0c;以避免多线程同时访问同一数据导致的竞争条…

在SPringBoot生成验证码

1.引入依赖,这个依赖中包含了生成验证码的工具类 <!--引入hutool --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.9</version></dependency> 2.编写配置类 import cn.hu…

Linux字符设备操作函数

Linux字符设备操作函数是指对字符设备进行打开、关闭、读取、写入、控制等基本操作的函数&#xff0c;它们通过字符设备结构体中的 file_operations 结构体来定义。常用的字符设备操作函数包括&#xff1a; 1、open: 当一个进程试图打开设备文件时&#xff0c;调用这个函数。开…

华润燃气牵手腾讯云 数字技术助力燃气行业高质量发展

7月13日&#xff0c;华润燃气与腾讯云正式签署战略合作协议。双方将充分发挥各自优势&#xff0c;探索AI大模型在燃气行业的深度应用&#xff0c;并深耕分布式计算、连接和客户运营等领域&#xff0c;不断提升燃气民生服务的效率、质量&#xff0c;共同推动行业数字化转型和高质…

ASEMI快恢复二极管MUR20100CTR在电子工程中的应用

编辑-Z 随着电子技术的日益发展&#xff0c;各种电子元件的使用场景与需求也在逐步扩大。今天&#xff0c;我们将聚焦于一款广泛应用于各类电路的二极管——MUR20100CTR&#xff0c;来详细解读其性能特征及应用。 一、MUR20100CTR二极管的主要特性 MUR20100CTR是一款极高性能的…

DataTable数据对比

DataTable数据对比 文章目录 DataTable数据对比前言一、计算DataTable差集结构不同的情况结构相同的情况 二、计算DataTable交集结构不同的情况结构相同的情况 三、计算DataTable的并集合两个DaTable结构相同的情况计算并集 前言 开发中我们经常会出现查询数据库后返回DataTab…

【iOS安全】iphone出现support.apple.com/iphone/restore

解决iphone出现support.apple.com/iphone/restore 解决方法1&#xff1a;使用爱思助手 可能是因为手机进入了恢复模式 手机连接Mac端的爱思助手之后&#xff0c;使用爱思助手的“退出恢复模式” 经测试有效 解决方法2&#xff1a;iphone强制重启 强制重新启动iPhone8或iPhone…

[Java]Set、Map、List常见实现类的特点、使用方法总结

文章目录 1、图谱2、List1、ArrayList1. 特点2. 常见方法 2、LinkedList1、特点2、常见方法 3、Vector1、特点 3、Map1、HashMap1、特点常用方法 2、TreeMap1、特点 3、LinkedHashMap1、特点 4、Set1、HashSet1 、特点2、常用方法 2、LinkedHashSet特点 3、TreeSet1、特点2、使…

Python - Django 框架 - 设置SECRET_KEY

在Django中&#xff0c;SECRET_KEY是一个重要的配置项&#xff0c;用于加密和保护用户数据、会话和其他敏感信息。下面是设置SECRET_KEY的几种常见方法&#xff1a; 1、在settings.py文件中硬编码设置&#xff1a; 打开项目中的settings.py文件&#xff0c;并在其中定义一个字…

SEED实验复现

SEED 项目由雪城大学教授杜文亮于 2002 年启动雪城大学。它由美国总共1万美元资助 美国国家科学基金会。现在&#xff0c;SEED 实验室正在被超过 全球数千个研究所。SEED 代表 &#xff08;SEcurity EDucaton&#xff09;。 https://github.com/seed-labs/seed-labs 该项目使用…

C++牛客WebServer项目学习笔记一

1.Linux系统命令&#xff1a; sudo apt install softname # sudo 管理员权限&#xff1b;apt 安装软件命令&#xff1b;ps -ef | grep ssh # ps 查看进程命令&#xff1b;| 管道符&#xff1b;grep 过滤出&#xff08;过滤出ssh关键词&#xff09;&#xff1b; 3.Ctrl滚动鼠标…