[LOJ#6002]「网络流 24 题」最小路径覆盖
[LOJ#6002]「网络流 24 题」最小路径覆盖
试题描述
给定有向图 G=(V,E)。设 P 是 G 的一个简单路(顶点不相交)的集合。如果 V 中每个顶点恰好在 P 的一条路上,则称 P 是 G 的一个路径覆盖。P 中路径可以从 V 的任何一个顶点开始,长度也是任意的,特别地,可以为 0。G 的最小路径覆盖是 G 的所含路径条数最少的路径覆盖。
设计一个有效算法求一个有向无环图 G 的最小路径覆盖。
输入
接下来的 m 行,每行有 2 个正整数 u 和 v,表示一条有向边 (i,j)。
输出
文件的最后一行是最少路径数。
输入示例
输出示例
数据规模及约定
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 题」最小路径覆盖的更多相关文章
- 【刷题】LOJ 6002 「网络流 24 题」最小路径覆盖
题目描述 给定有向图 \(G = (V, E)\) .设 \(P\) 是 \(G\) 的一个简单路(顶点不相交)的集合.如果 \(V\) 中每个顶点恰好在 \(P\) 的一条路上,则称 \(P\) 是 ...
- LibreOJ #6002. 「网络流 24 题」最小路径覆盖
#6002. 「网络流 24 题」最小路径覆盖 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测 ...
- Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流)
Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流) Description 给定有向图G=(V,E).设P是G的一个简单路(顶点不相 ...
- LOJ6002 - 「网络流 24 题」最小路径覆盖
原题链接 Description 求一个DAG的最小路径覆盖,并输出一种方案. Solution 模板题啦~ Code //「网络流 24 题」最小路径覆盖 #include <cstdio&g ...
- [luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划
[luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划 试题描述 一个餐厅在相继的 \(N\) 天里,第 \(i\) 天需要 \(R_i\) 块餐巾 \((i=l,2,-,N)\) ...
- 【刷题】LOJ 6227 「网络流 24 题」最长k可重线段集问题
题目描述 给定平面 \(\text{xoy}\) 上 \(n\) 个开线段组成的集合 \(\text{I}\) ,和一个正整数 \(k\) ,试设计一个算法. 从开线段集合 \(\text{I}\) ...
- [loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流
#6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 ...
- loj #6013. 「网络流 24 题」负载平衡
#6013. 「网络流 24 题」负载平衡 题目描述 G 公司有 n nn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n nn 个仓库的库存数量相同.搬运货物时 ...
- LOJ #6008. 「网络流 24 题」餐巾计划
#6008. 「网络流 24 题」餐巾计划 题目描述 一个餐厅在相继的 n nn 天里,每天需用的餐巾数不尽相同.假设第 i ii 天需要 ri r_iri 块餐巾.餐厅可以购买新的餐巾,每块餐 ...
随机推荐
- 【转载】Cesium基础使用介绍
既然给我发了参与方式,不参加似乎有点不给人面子,反正也没多少人看我的博客,那我就试试吧,也欢迎大家自己参与:2017年度全网原创IT博主评选活动投票:http://www.itbang.me/goVo ...
- bzoj3209:3209: 花神的数论题
觉得还是数位dp的那种解题形式但是没有认真的想,一下子就看题解.其实还是设置状态转移.一定要多思考啊f[i][j]=f[i-1][j]+g[i-1][j] g[i][j]=f[i-1][j-1]+g[ ...
- Mycat实现读写分离、分库分表
系统开发中,数据库是非常重要的一个点.除了程序的本身的优化,如:SQL语句优化.代码优化,数据库的处理本身优化也是非常重要的.主从.热备.分表分库等都是系统发展迟早会遇到的技术问题问题.Mycat是一 ...
- HTML_6 (表单应用)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- ubuntu18.04 安装五笔拼音
sudo apt install fcitx-table-wubi fcitx-table-wbpy 在输入法中加入五笔拼音就可以了,如果原来使用的是ibus, 改为fcitx后,重启机器.
- 《队长说得队》【Alpha】Scrum meeting 2
项目 内容 这个作业属于哪个课程 >>2016级计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 >>实验十二 团队作业8:软件测试与ALPHA冲刺 团队名称 ...
- Visual Studio Professional 2015 简体中文专业版 序列号
Visual Studio Professional 2015 简体中文专业版 专业版激活密钥:HMGNV-WCYXV-X7G9W-YCX63-B98R2 Visual Studio Enterpri ...
- iOS快速开发框架--Bee Framework
Bee Framework是一款iOS快速开发框架,允许开发者使用Objective-C和XML/CSS来进行iPhone和iPad开发,由 Gavin Kwoe 和 QFish 开发并维护. 其早期 ...
- skynet 学习笔记-netpack模块(1)
int luaopen_netpack(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { { "pop", lpop } ...
- module.exports exports 和export export default
首先可以知道的是这是两组不同模块规范. module.exports 是CommonJS模块规范,通过require 导入 a.js: var x = 'hello' module.exports.x ...