网络流 \(24\) 题之一。

Problem

Description

给出一个 \(n\) 个点 \(m\) 条边的 \(DAG\) ,求最小路径点覆盖,并输出路径选择方案。

Input Format

第一行有 \(2\) 个正整数 \(n\) 和 \(m\) 。 \(n\) 是给定\(\text{GAP}\)(有向无环图) \(G\) 的顶点数, \(m\) 是 \(G\) 的边数。接下来的 \(m\) 行,每行有两个正整数 \(i\) 和 \(j\) 表示一条有向边 \((i,j)\)。

Output Format

从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

Sample

Input

11 12
1 2
1 3
1 4
2 5
3 6
4 7
5 8
6 9
7 10
8 11
9 11
10 11

Output

1 4 7 10 11
2 5 8
3 6 9
3

Range

\(1\leq n\leq 150,1\leq m\leq 6000\)

Mentality

这题其实就是 \(DAG\) 上的最小路径点覆盖,详情参考这篇 \(blog\)

其实这里只要叙述怎么处理方案的输出就好了 ......

我们对于二分图跑完最大流之后,扫一遍二分图中所有的边 (并不包括连向超级源点汇点的边) ,根据网络流残余网络的特性,如果某一条边的反边中剩余容量不为 \(0\) ,那么它必定是最大流中的一条可行弧。则我们记录下这条边,对于左侧点 \(i\) ,记录一个 \(next[i]\) 代表 \(i\) 连向的边,并记录右侧点 \(j'\) 是否被经过。接着,我们扫一遍右边的点,如果 \(i'\) 没有被任何一条边经过,则入度为 \(0\) ,必定为路径起点,那么我们从 \(i\) 开始借助 \(next\) 数组遍历这条路径并输出即可。

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int n, m, S, T;
int head[1001], nx[20001], to[20001], w[20001], cnt;
int deep[1001], nt[1001];
bool book[20001], r[1001];
int inf = 1e9, ans;
void add(int u, int v, int W, int d) {
to[d] = v, nx[d] = head[u], w[d] = W;
head[u] = d;
}
queue<int> q;
bool init() {
memset(book, 0, sizeof(book));
memset(deep, -1, sizeof(deep));
deep[S] = 1;
q.push(S);
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = head[x]; i; i = nx[i])
if (deep[to[i]] == -1 && w[i] > 0) {
deep[to[i]] = deep[x] + 1;
q.push(to[i]);
}
}
return deep[T] != -1;
}
int dfs(int x, int limit) {
if (x == T || !limit) return limit;
int flow = 0, fnow;
for (int i = head[x]; i; i = nx[i])
if (deep[to[i]] == deep[x] + 1 && !book[i] &&
(fnow = dfs(to[i], min(limit, w[i])))) {
book[i] = true;
flow += fnow;
limit -= fnow;
w[i] -= fnow;
w[i ^ 1] += fnow;
if (!limit) break;
}
return flow;
}
void print(int x) {
if (!x) return;
printf("%d ", x);
print(nt[x]);
}
int main() {
cin >> n >> m;
S = n * 2 + 1, T = n * 2 + 2, cnt = 1;
for (int i = 1; i <= n; i++) {
add(S, i, 1, ++cnt);
add(i, S, 0, ++cnt);
add(i + n, T, 1, ++cnt);
add(T, i + n, 0, ++cnt);
}
int u, v;
for (int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
v += n;
add(u, v, inf, ++cnt);
add(v, u, 0, ++cnt);
}
while (init()) dfs(S, inf);
for (int i = 2; i <= cnt; i += 2) {
int p1 = to[i], p2 = to[i ^ 1];
if (p1 == S || p1 == T || p2 == S || p2 == T) continue;
if (w[i ^ 1]) nt[to[i ^ 1]] = to[i] - n, r[to[i] - n] = true;
}
for (int i = 1; i <= n; i++)
if (!r[i]) {
ans++;
print(i);
cout << endl;
}
cout << ans;
}

【Luogu P2764】最小路径覆盖问题的更多相关文章

  1. Luogu P2764 最小路径覆盖问题(二分图匹配)

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

  2. luogu P2764 最小路径覆盖问题

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

  3. LUOGU P2764 最小路径覆盖问题 (最小路径点覆盖)

    解题思路 有向图最小路径点覆盖问题,有这样的结论就是有向图最小路径点覆盖等于n-拆点二分图中最大匹配.具体怎么证明不太知道..输出方案时找到所有左部未匹配的点一直走$match​$就行了. #incl ...

  4. 【luogu P2764 最小路径覆盖问题】 模板

    题目链接:https://www.luogu.org/problemnew/show/P2764 把每个点在左边建一遍右边建一遍,再加上源点汇点,跑最大流,n-最大流就是答案. #include &l ...

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

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

  6. Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流)

    Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流) Description 给定有向图G=(V,E).设P是G的一个简单路(顶点不相 ...

  7. P2764 最小路径覆盖问题 网络流重温

    P2764 最小路径覆盖问题 这个题目之前第一次做的时候感觉很难,现在好多了,主要是二分图定理不太记得了,二分图定理 知道这个之后就很好写了,首先我们对每一个点进行拆点,拆完点之后就是跑最大流,求出最 ...

  8. 【Luogu】P2764最小路径覆盖(拆点求最大匹配)

    题目链接 这个……学了一条定理 最小路径覆盖=原图总点数-对应二分图最大匹配数 这个对应二分图……是什么呢? 就是这样 这是原图 这是拆点之后对应的二分图. 然后咱们的目标就是从这张图上跑出个最大流来 ...

  9. 洛谷 P2764 最小路径覆盖问题【最大流+拆点+路径输出】

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

  10. 网络流二十四题之P2764 最小路径覆盖问题

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

随机推荐

  1. 做一次面向对象的体操:将JSON字符串转换为嵌套对象的一种方法

    背景与问题 在 <一个略复杂的数据映射聚合例子及代码重构> 一文中,将一个JSON字符串转成了所需要的订单信息Map.尽管做了代码重构和配置化,过程式的代码仍然显得晦涩难懂,并且客户端使用 ...

  2. flask 在模板中渲染表单

    在模板中渲染表单 为了能够在模板中渲染表单,我们需要把表单类实例传入模板.首先在视图函数里实例化表单类LoginForm,然后再render_template()函数中使用关键脑子参数form将表单实 ...

  3. ClassThree__HomeWork

    作业一 使用类的静态字段和构造函数,可以跟踪某个类所创建对象的个数.请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象?”. 代码 public class TestOne {       ...

  4. 开始Nginx的SSL模块

    nginx: [emerg] the "ssl" parameter requires ngx_http_ssl_module in /usr/local/nginx/conf/n ...

  5. python 之xml.etree.ElementTree

    Element类型是一种灵活的容器对象,用于在内存中存储结构化数据. [注意]xml.etree.ElementTree模块在应对恶意结构数据时显得并不安全. 每个element对象都具有以下属性: ...

  6. NFS客户端阻塞睡眠问题与配置调研

    Linux NFS客户端需要很小心地配置,否则在NFS服务器崩溃时,访问NFS的程序会被挂起,用ps查看,进程状态(STAT)处于D,意为(由于IO阻塞而进入)不可中断睡眠(如果是D+,+号表示程序运 ...

  7. oj练习---dp专题

    1.POJ 3744 Scout YYF I 经典的dp模型,但是要用到快速矩阵幂加速,分段的思想 # include <stdio.h> # include <algorithm& ...

  8. 容器学习笔记之CentOS7安装Docker(安装指定版本的Docker,加速,卸载)

    0x00 概述 Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE. 社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收费服务,比如经过官方测试认证过 ...

  9. Redis Desktop Manager 利用ssh连接 Redis

    需开启6379端口,如果不设置密码,就忽略1,2步骤 第一步: 第二步: 第三步: 第四步: 第五步:

  10. python的类和实例化对象

    一切皆对象,类也是对象,类来自于元类type,如果一个类没有声明自己的元类,默认它就是元类. 即类是元类的实例,通过type(类)会显示type,而实例来自于类. 类有两个属性,数据属性和函数属性,下 ...