[LOJ#6002]「网络流 24 题」最小路径覆盖

试题描述

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

设计一个有效算法求一个有向无环图 G 的最小路径覆盖。

输入

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

输出

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

输入示例


输出示例


数据规模及约定

1≤n≤200,1≤m≤6000

题解

练一下 Dinic 模板。

最小路径覆盖是经典题了。

首先我们假定每个节点都是一个路径,考虑尽量多地合并某两条路径。

不难发现一条路径的贡献可以看成这条路径的节点个数减去边数,并且每个点只能属于一条路径,那么如果把原图上的每个点拆成入和出两个点,那么会发现这个问题转化成了二分图匹配,答案等于原图总点数 - 二分图最大匹配数。

对于所有入点没有被匹配上的点,就是原图中路径的起点,然后沿着这个起点不停地找“出点——入点”的匹配边,找出整个路径。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 410
#define maxm 12410
#define oo 2147483647 struct Edge {
int from, to, flow;
Edge() {}
Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
} ;
struct Dinic {
int n, m, s, t, head[maxn], nxt[maxm];
Edge es[maxm];
int vis[maxn], Q[maxn], hd, tl;
int cur[maxn]; void init() {
m = 0; memset(head, -1, sizeof(head));
return ;
}
void setn(int _n) {
n = _n;
return ;
} void AddEdge(int a, int b, int c) {
es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
return ;
} bool BFS() {
memset(vis, 0, sizeof(vis));
hd = tl = 0; Q[++tl] = s; vis[s] = 1;
while(hd < tl) {
int u = Q[++hd];
for(int i = head[u]; i != -1; i = nxt[i]) {
Edge& e = es[i];
if(!vis[e.to] && e.flow) vis[e.to] = vis[u] + 1, Q[++tl] = e.to;
}
}
return vis[t] > 1;
}
int DFS(int u, int a) {
if(u == t || !a) return a;
int flow = 0, f;
for(int& i = cur[u]; i != -1; i = nxt[i]) {
Edge& e = es[i];
if(vis[e.to] == vis[u] + 1 && (f = DFS(e.to, min(a, e.flow)))) {
flow += f; a -= f;
e.flow -= f; es[i^1].flow += f;
if(!a) return flow;
}
}
return flow;
}
int MaxFlow(int _s, int _t) {
s = _s; t = _t;
int flow = 0;
while(BFS()) {
for(int i = 1; i <= n; i++) cur[i] = head[i];
flow += DFS(s, oo);
}
return flow;
}
} sol; int CntP;
struct Point {
int id;
Point(): id(0) {}
int p() { return id ? id : id = ++CntP; }
} inu[maxn], outu[maxn], S, T;
int tmp[maxn], cntt, uid[maxn]; int main() {
int n = read(), m = read();
sol.init(); S.p(); T.p();
for(int i = 1; i <= n; i++)
sol.AddEdge(S.p(), outu[i].p(), 1), uid[outu[i].p()] = i,
sol.AddEdge(inu[i].p(), T.p(), 1), uid[inu[i].p()] = i;
for(int i = 1; i <= m; i++) {
int a = read(), b = read();
sol.AddEdge(outu[a].p(), inu[b].p(), 1);
} sol.setn(CntP);
int ans = n - sol.MaxFlow(S.p(), T.p());
for(int i = 1; i <= n; i++) {
bool iss = 0;
for(int t = sol.head[inu[i].p()]; t != -1; t = sol.nxt[t]) {
Edge& e = sol.es[t];
if(e.to == T.p() && e.flow){ iss = 1; break; }
}
if(!iss) continue;
int node = i; cntt = 0; tmp[++cntt] = node;
for(;;) {
bool has = 0;
for(int t = sol.head[outu[node].p()]; t != -1; t = sol.nxt[t]) {
Edge& e = sol.es[t];
if(e.to != S.p() && !e.flow){ has = 1; tmp[++cntt] = node = uid[e.to]; break; }
}
if(!has) break;
}
for(int i = 1; i <= cntt; i++) printf("%d%c", tmp[i], i < cntt ? ' ' : '\n');
}
printf("%d\n", ans); return 0;
}

[LOJ#6002]「网络流 24 题」最小路径覆盖的更多相关文章

  1. 【刷题】LOJ 6002 「网络流 24 题」最小路径覆盖

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

  2. LibreOJ #6002. 「网络流 24 题」最小路径覆盖

    #6002. 「网络流 24 题」最小路径覆盖 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测 ...

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

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

  4. LOJ6002 - 「网络流 24 题」最小路径覆盖

    原题链接 Description 求一个DAG的最小路径覆盖,并输出一种方案. Solution 模板题啦~ Code //「网络流 24 题」最小路径覆盖 #include <cstdio&g ...

  5. [luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划

    [luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划 试题描述 一个餐厅在相继的 \(N\) 天里,第 \(i\) 天需要 \(R_i\) 块餐巾 \((i=l,2,-,N)\) ...

  6. 【刷题】LOJ 6227 「网络流 24 题」最长k可重线段集问题

    题目描述 给定平面 \(\text{xoy}\) 上 \(n\) 个开线段组成的集合 \(\text{I}\) ,和一个正整数 \(k\) ,试设计一个算法. 从开线段集合 \(\text{I}\) ...

  7. [loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流

    #6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 ...

  8. loj #6013. 「网络流 24 题」负载平衡

    #6013. 「网络流 24 题」负载平衡 题目描述 G 公司有 n nn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n nn 个仓库的库存数量相同.搬运货物时 ...

  9. LOJ #6008. 「网络流 24 题」餐巾计划

    #6008. 「网络流 24 题」餐巾计划 题目描述 一个餐厅在相继的 n nn 天里,每天需用的餐巾数不尽相同.假设第 i ii 天需要 ri r_ir​i​​ 块餐巾.餐厅可以购买新的餐巾,每块餐 ...

随机推荐

  1. 2012-2013 ACM-ICPC, NEERC, Central Subregional Contest H Milestones1 (暴力)

    预处理+暴力,每个颜色都是独立的,求个前缀和,减一减判断一个在区间内颜色是否存在. 算了算复杂度好像有点勉强,但是还是过了,学了主席树以后用主席树在做一下 #include<bits/stdc+ ...

  2. python 基础之格式化输出

    字符占位符%s #_cvvh:"chenxi" #date: 2019/6/24 print ('chhjg') # 格式化输出 name = input("Name:& ...

  3. 变量和数据类型&运算符

    变量和数据类型&运算符 变量 变量的作用:用来存储数据 变量命名的规范:字(字符串)下(_下划线)美($)人(¥) 数 (可以包括数字)骆驼 有意义(可以以字母,下划线,美元符号,人民币符号开 ...

  4. php的字符转换 & php登入注册界面设计以及源码 & 分离公共部分

    我们在编写的时候总是会出现乱码 https://www.cnblogs.com/mafeng/p/5827215.html php登入注册界面设计以及源码 https://blog.csdn.net/ ...

  5. SAP行列转换的一种方法

    一段经典的代码写在这里 TABLES spfli. DATA: lt_data TYPE STANDARD TABLE OF spfli, lwa_ref TYPE REF TO data, lt_f ...

  6. MySQL查询显示连续的结果

    #mysql中 对于查询结果只显示n条连续行的问题# 在领扣上碰到的一个题目:求满足条件的连续3行结果的显示 X city built a new stadium, each day many peo ...

  7. linux下GPIO的用户层操作(sysfs)

    linux的GPIO通过sysfs为用户提供服务,下面是linux kernel里的说明文档,学习一下. GPIO Sysfs Interface for Userspace ============ ...

  8. leepcode作业解析-5-21

    25.Nim游戏 你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头. 拿掉最后一块石头的人就是获胜者.你作为先手. 你们是聪明人,每一步都是最优解. 编 ...

  9. linux中vim永久显示行号、开启语法高亮

    vim ~/.vimrc 进入insert模式,在最后加二行 syntax on set nu! 保存收工. 设置用视图模式的缩进为4个空格 set smartindent set tabstop=4 ...

  10. python列表中的深浅copy

    列表中的赋值和平常的赋值是不一样的,看下面的代码: In [1]: a = 1 In [2]: b = a In [3]: a Out[3]: 1 In [4]: b Out[4]: 1 In [5] ...