洛谷P2764 最小路径覆盖问题

时间:2022-10-21 11:25:16

有向无环图的最小路径点覆盖

最小路径覆盖就是给定一张DAG,要求用尽量少的不相交的简单路径,覆盖有向无环图的所有顶点。

有定理:顶点数-路径数=被覆盖的边数。

要理解的话可以从两个方向:

  • 假设DAG已经被n条路径覆盖,那么任意一条路径又有 顶点数-1=边数。那么对所有路径等式两边求和,每条路径的顶点数之和=所有点数,-1的和=路径数,每条路径的边数之和=被覆盖的边数。。这样上面的定理就成立了。

  • 还有一种方法,我们要先引入二分图

我们把原图中的点拆成出点(边从该点出)和入点(边从该点入),即原图点x在二分图中对应出点x,入点x+n。

原图中的边(x,y)对应二分图中的(x,y+n)。我们每次选择路径,因为边不能相交,所以对于一个点,只有一个入和一个出,这显然是一个匹配问题。

选择的边(x,y)相当于从源点s到x,从x到y+n,从y+n到汇点t有了单位流量。

特别的,如果一个点是路径的终点,那么他没有出度,即该点二分匹配失败。

可以显然得出,最后匹配失败的点数就是路径数。

因为源点相连的点一定有n个,所以有 顶点数-路径数=二分图最大匹配。

且由上述概念得二分图最大匹配即为路径选择的边数(被覆盖的边数)

所以我们把题目给的点拆开跑最大流就可以啦!

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
int X = 0, w = 0; char ch = 0;
while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
return w ? -X : X;
}
inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
A ans = 1;
for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
return ans;
}
const int N = 505;
const int M = 6005;
int n, m, cnt, head[N], depth[N], to[N], vis[N];
struct Edge { int v, next, f; } edge[M<<5]; void addEdge(int a, int b, int f){
edge[cnt].v = b, edge[cnt].f = f, edge[cnt].next = head[a], head[a] = cnt ++;
edge[cnt].v = a, edge[cnt].f = 0, edge[cnt].next = head[b], head[b] = cnt ++;
} bool bfs(){
full(depth, 0);
queue<int> q;
depth[0] = 1, q.push(0);
while(!q.empty()){
int s = q.front(); q.pop();
for(int i = head[s]; i != -1; i = edge[i].next){
int u = edge[i].v;
if(!depth[u] && edge[i].f > 0){
depth[u] = depth[s] + 1;
q.push(u);
}
}
}
return depth[2 * n + 1] != 0;
} int dfs(int s, int a){
if(s == 2 * n + 1) return a;
int flow = 0;
for(int i = head[s]; i != -1; i = edge[i].next){
int u = edge[i].v;
if(depth[u] == depth[s] + 1 && edge[i].f > 0){
int k = dfs(u, min(a, edge[i].f));
if(k > 0){
flow += k, a -= k, edge[i].f -= k, edge[i^1].f += k, to[s] = u;
if(s != 0) vis[u - n] = true;
}
}
if(!a) break;
}
if(a) depth[s] = -1;
return flow;
} int dinic(){
int ret = 0;
while(bfs()){
ret += dfs(0, INF);
}
return ret;
} int main(){ full(head, -1);
n = read(), m = read();
for(int i = 1; i <= n; i ++)
addEdge(0, i, 1), addEdge(i + n, 2 * n + 1, 1);
for(int i = 0; i < m; i ++){
int u = read(), v = read();
addEdge(u, v + n, 1);
}
int ans = n - dinic();
for(int i = 1; i <= n; i ++){
if(!vis[i]){
int cur = i;
printf("%d ", cur);
while(to[cur] != 2 * n + 1 && to[cur] != 0){
printf("%d ", to[cur] - n), cur = to[cur] - n;
}
puts("");
}
}
printf("%d\n", ans);
return 0;
}

洛谷P2764 最小路径覆盖问题的更多相关文章

  1. 洛谷 P2764 最小路径覆盖问题 解题报告

    P2764 最小路径覆盖问题 问题描述: 给定有向图\(G=(V,E)\).设\(P\) 是\(G\) 的一个简单路(顶点不相交)的集合.如果\(V\) 中每个顶点恰好在\(P\) 的一条路上,则称\ ...

  2. 洛谷 P2764 最小路径覆盖问题【最大流&plus;拆点&plus;路径输出】

    题目链接:https://www.luogu.org/problemnew/show/P2764 题目描述 «问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V ...

  3. 【刷题】洛谷 P2764 最小路径覆盖问题

    题目描述 «问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖.P 中路径可以从V 的任何一个顶点开 ...

  4. 洛谷P2764 最小路径覆盖问题(最大流)

    传送门 先说做法:把原图拆成一个二分图,每一个点被拆成$A_i,B_i$,若原图中存在边$(u,v)$,则连边$(A_u,B_v)$,然后$S$对所有$A$连边,所有$B$对$T$连边,然后跑一个最大 ...

  5. 洛谷 P2764 最小路径覆盖问题【匈牙利算法】

    经典二分图匹配问题.把每个点拆成两个,对于原图中的每一条边(i,j)连接(i,j+n),最小路径覆盖就是点数n-二分图最大匹配.方案直接顺着匹配dsf.. #include<iostream&g ...

  6. 洛谷 P2764&lpar;最小路径覆盖&equals;节点数-最大匹配&rpar;

    给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖.P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别 ...

  7. 洛谷P2764 最小路径覆盖问题&lpar;二分图&rpar;

    题意 给出一张有向无环图,求出用最少的路径覆盖整张图,要求路径在定点处不相交 输出方案 Sol 定理:路径覆盖 = 定点数 - 二分图最大匹配数 直接上匈牙利 输出方案的话就不断的从一个点跳匹配边 # ...

  8. 洛谷 &lbrack;P2764&rsqb;最小路径覆盖问题

    二分图应用模版 #include <iostream> #include <cstdio> #include <algorithm> #include <cs ...

  9. 洛谷-p2764&lpar;最小路径覆盖&rpar;(网络流24题)

    #include<iostream> #include<algorithm> #include<queue> #include<cstring> #in ...

随机推荐

  1. 从Membership 到 &period;NET4&period;5 之 ASP&period;NET Identity

    我们前面已经讨论过了如何在一个网站中集成最基本的Membership功能,然后深入学习了Membership的架构设计.正所谓从实践从来,到实践从去,在我们把Membership的结构吃透之后,我们要 ...

  2. 1、网页制作Dreamweaver(界面、基本操作、锚点、表格)

    界面 网页的界面html由两部分组成:<head>和<body>,<title>放在<head>中 1.以下是<head>部分的解释: &l ...

  3. 高性能mysql主主架构

    A.环境描述 服务器A(主) 192.168.0.105 服务器B(主) 192.168.0.108 Mysql版本: 5.6.21 System OS:CentOS release 6.5 主从需同 ...

  4. winfrom播放动态图片

    winfrom是不能直接加载的动态图片的.只能够自己写方法实现. 具体代码如下: using System; using System.Collections.Generic; using Syste ...

  5. 树莓派远程桌面配置-开机自启SSH

    必须先安装tightvncserver sudo apt-get install tightvncserver 再安装xrdp服务. sudo apt-get install xrdp 如果开着防火墙 ...

  6. spring的bean是在什么时候实例化的

    如果没有特殊配置,当bean的scope为原型,也就是singleton的时候,在启动spring容器的时候完成实例化.且需要注意的是,当实例化一个bean的时候,先执行其构造函数代码,然后再执行se ...

  7. 2018-2019-2 网络对抗技术 20165317 Exp3 免杀原理与实践

    2018-2019-2 网络对抗技术 20165317 Exp3 免杀原理与实践 实验内容 任务一:正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用 ...

  8. linux下统计文本行数的各种方法

    方法一:awk  awk '{print NR}' test1.txt | tail -n1

  9. js将时间戳转为时间格式

    时间戳转时间格式 //分钟 let timeM= parseInt(msg/1000/60%60); if(timeM<10){ timeM="0"+timeM; } //秒 ...

  10. JavaScript test&lpar;&rpar; 方法

    JavaScript test() 方法 JavaScript RegExp 对象 定义和用法 test() 方法用于检测一个字符串是否匹配某个模式. 语法 RegExpObject.test(str ...