「网络流 24 题」最小路径覆盖 【最小路径覆盖】

「网络流 24 题」最小路径覆盖

思路

具体可以看 这篇博客

对于有向无环图 ,我们只需要将假装 将点裂成左点和右点(实际没有裂开),然后连边;

在上面跑二分图最大匹配 后,剩下没有匹配的左点就是终点 (因为它没有匹配,没有出边了),没有匹配的右点就是起点(因为没有点能够到达它)

那么最小路径覆盖数就是: 点数 − 最大匹配数 点数 - 最大匹配数 点数−最大匹配数

对于输出路径划分方案,我们可以利用 m a t c h match match 数组,因为 u = m a t c h [ v ] u = match[v] u=match[v] 记录的就是 u → v u \rarr v u→v 这条边,并且是最小路径覆盖,那么 v v v 的唯一入度就是 u u u,所以我们可以线性处理

最终从每条路径的起点搜索输出即可

时间复杂度: O ( n m ) O(nm) O(nm)

cpp 复制代码
// Problem: #6002. 「网络流 24 题」最小路径覆盖
// Contest: LibreOJ
// URL: https://loj.ac/p/6002
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 
#define ull unsigned long long

const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;

typedef long long ll;

const int N = 250;

std::vector<int> match; //match[i]表示每个右点i当前匹配的左点
std::vector<bool> used; //当前轮 右点 i 是否被预定
std::vector<int> g[N];

bool dfs(int l){ //为当前左点 l 寻找匹配
    for(auto r : g[l])
        if(!used[r]){ //如果当前轮右点r还没有被预订
            used[r] = true; //预定
            if(!match[r] || dfs(match[r])){
                match[r] = l;
                return true;
//(1)如果右点 r 还没有配对
//(2)右点 r 已经配对,尝试更换其原配左点
            }
        }
    return false;
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int n, m;
    std::cin >> n >> m;
    match.assign(n + 1, 0);
    while(m--){
    	int u, v;
    	std::cin >> u >> v;
    	g[u].push_back(v);
    }
    
    std::vector<int> nxt(n + 1, 0);
    
    int cnt = 0;
    fore(i, 1, n + 1){
    	used.assign(n + 1, false);
    	cnt += dfs(i);
    }
    
    std::vector<bool> head(n + 1, true); //是否为起点
    fore(v, 1, n + 1){
    	int u = match[v];
    	if(!u)	continue;
    	nxt[u] = v;
    	head[v] = false;
    }
    
    fore(i, 1, n + 1){
    	if(!head[i])	continue;
    	int u = i; //从起点开始搜,路径唯一
    	while(nxt[u]){
    		std::cout << u << ' ';
    		u = nxt[u];
    	}
    	std::cout << u << endl;
    }
    
    std::cout << n - cnt; //最小路径覆盖数量
    
	return 0; 
}
相关推荐
Eward-an33 分钟前
LeetCode 1980 题通关指南|3种解法拆解“找唯一未出现二进制串”问题,附Python最优解实现
python·算法·leetcode
程序员酥皮蛋1 小时前
hot 100 第四十题 40.二叉树的层序遍历
数据结构·算法·leetcode
木斯佳2 小时前
HarmonyOS 6实战:从爆款vlog探究鸿蒙智能体提取关键帧算法
算法·华为·harmonyos
Mr.朱鹏3 小时前
JVM-GC垃圾回收案例
java·jvm·spring boot·算法·spring·spring cloud·java-ee
WJSKad12353 小时前
【DepthPro】实战教程:单目深度估计算法详解与应用
算法
wzqllwy3 小时前
8 大经典排序算法(Java 实现):原理 + Demo + 核心分析
java·算法·排序算法
We་ct3 小时前
LeetCode 77. 组合:DFS回溯+剪枝,高效求解组合问题
开发语言·前端·算法·leetcode·typescript·深度优先·剪枝
重生之我是Java开发战士3 小时前
【递归、搜索与回溯】二叉树中的深度优先搜索:布尔二叉树,求根节点到叶节点数字之和,二叉树剪枝,验证二叉搜索树,第K小的元素,二叉树的所有路径
算法·深度优先·剪枝
篮l球场3 小时前
矩阵置零
算法
lihihi3 小时前
P1650 [ICPC 2004 Shanghai R] 田忌赛马(同洛谷2587)
开发语言·算法·r语言