DAG的最小路径覆盖

定义:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点。

最小路径覆盖分为最小不相交路径覆盖和最小可相交路径覆盖。

最小不相交路径覆盖:每一条路径经过的顶点各不相同。如图,其最小路径覆盖数为3。即1->3>4,2,5。

最小可相交路径覆盖:每一条路径经过的顶点可以相同。如果其最小路径覆盖数为2。即1->3->4,2->3>5。

特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0。

DAG的最小不相交路径覆盖

算法:把原图的每个点V拆成$V_x$和$V_y$两个点,如果有一条有向边A->B,那么就加边$A_x->B_y$。这样就得到了一个二分图。那么最小路径覆盖=原图的结点数-新图的最大匹配数。

证明:一开始每个点都是独立的为一条路径,总共有n条不相交路径。我们每次在二分图里找一条匹配边就相当于把两条路径合成了一条路径,也就相当于路径数减少了1。所以找到了几条匹配边,路径数就减少了多少。所以有最小路径覆盖=原图的结点数-新图的最大匹配数。

因为路径之间不能有公共点,所以加的边之间也不能有公共点,这就是匹配的定义。

习题:POJ1422

//
// main.cpp
// POJ1422最小不想交路径覆盖
//
// Created by beMaster on 16/4/8.
// Copyright © 2016年 beMaster. All rights reserved.
// #include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
const int N = + ;
vector<int> g[N];
int cy[N];
bool vis[N];
bool dfs(int u){
for(int i=; i<g[u].size(); ++i){
int v = g[u][i];
if(vis[v]) continue;
vis[v] = true;
if(cy[v]==- || dfs(cy[v])){
cy[v] = u;
return true;
}
}
return false;
}
int solve(int n){
int ret = ;
memset(cy, -, sizeof(cy));
for(int i=;i<=n;++i){
memset(vis, , sizeof(vis));
ret += dfs(i);
}
return n - ret;
}
int main(int argc, const char * argv[]) {
int t,n,m;
int u,v;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)
g[i].clear();
for(int i=;i<m;++i){
scanf("%d%d",&u,&v);
g[u].push_back(v);
} int ans = solve(n);
printf("%d\n",ans);
}
return ;
}

DAG的最小可相交路径覆盖

算法:先用floyd求出原图的传递闭包,即如果a到b有路径,那么就加边a->b。然后就转化成了最小不相交路径覆盖问题。

证明:为了连通两个点,某条路径可能经过其它路径的中间点。比如1->3->4,2->4->5。但是如果两个点a和b是连通的,只不过中间需要经过其它的点,那么可以在这两个点之间加边,那么a就可以直达b,不必经过中点的,那么就转化成了最小不相交路径覆盖。

题目:POJ2594

//
// main.cpp
// POJ2594最小可相交路径覆盖
//
// Created by beMaster on 16/4/8.
// Copyright © 2016年 beMaster. All rights reserved.
// #include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
const int N = + ;
bool dis[N][N];
bool vis[N];
int cy[N];
void floyd(int n){
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
for(int k=;k<=n;++k)
if(dis[i][k] && dis[k][j])//传递可达性
dis[i][j] = true;
}
bool dfs(int u, int n){
for(int i=;i<=n;++i){
if(!vis[i] && dis[u][i]){
vis[i] = true;
if(cy[i]==- || dfs(cy[i], n)){
cy[i] = u;
return true;
}
}
}
return false;
}
int solve(int n){
int cnt = ;
memset(cy,-,sizeof(cy));
for(int i=;i<=n;++i){
memset(vis,,sizeof(vis));
cnt += dfs(i, n);
}
return n - cnt;
}
int main(int argc, const char * argv[]) {
int n,m;
int a,b;
while(scanf("%d%d",&n,&m),n+m){
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
dis[i][j] = false;
for(int i=;i<=m;++i){
scanf("%d%d",&a,&b);
dis[a][b] = true;
}
floyd(n);
int ans = solve(n);
printf("%d\n",ans);
}
return ;
}

参考:

二分图大讲堂——彻底搞定最大匹配数(最小覆盖数)、最大独立数、最小路径覆盖、带权最优匹配

有向无环图(DAG)的最小路径覆盖的更多相关文章

  1. 大数据工作流任务调度--有向无环图(DAG)之拓扑排序

    点击上方蓝字关注DolphinScheduler(海豚调度) |作者:代立冬 |编辑:闫利帅 回顾基础知识: 图的遍历 图的遍历是指从图中的某一个顶点出发,按照某种搜索方法沿着图中的边对图中的所有顶点 ...

  2. UVAlive3126 Taxi Cab Scheme(DAG的最小路径覆盖)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=32568 [思路] DAG的最小路径覆盖. 将每个人看做一个结点,如 ...

  3. C#实现有向无环图(DAG)拓扑排序

    对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在 ...

  4. 某种带权有向无环图(graph)的所有路径的求法

    // 讨论QQ群:135202158 最近做某个东西,最后用图实现了,这里总结一下算法. 假设有以下带权有向无环图(连通或非连通,我这里用的是非连通的): 每个节点(node)可能与其他节点有向地相连 ...

  5. UVALive-3126 Taxi Cab Scheme (DAG的最小路径覆盖)

    题目大意:要给n个人安排车,已知每个人的出发时间和起点与终点,问最少需要安排几辆车才能完成任务. 题目分析:最小路径覆盖.如果送完a到目的地后能在b出发之前赶来接b,那么连一条有向边a->b,最 ...

  6. POJ Treasure Exploration 【DAG交叉最小路径覆盖】

    传送门:http://poj.org/problem?id=2594 Treasure Exploration Time Limit: 6000MS   Memory Limit: 65536K To ...

  7. [笔记] 有向无环图 DAG

    最小链覆盖 (最长反链) 最小链覆盖 \(=n-\) 最大匹配. 考虑首先每个点自成一条链,此时恰好有 \(n\) 条链,最终答案一定是合并(首尾相接)若干条链形成的. 将两点匹配的含义其实就是将链合 ...

  8. 【模板整合计划】图论—有向无环图 (DAG) 与树

    [模板整合计划]图论-有向无环图 (DAG) 与树 一:[拓扑排序] 最大食物链计数 \(\text{[P4017]}\) #include<cstring> #include<cs ...

  9. 判断有向无环图(DAG)

    1.拓扑排序 bfs 所有入度为0的先入选. 2.tarjan 1个点1个集合 3.暴力 一个点不能重新到达自己

  10. hdu1151 二分图(无回路有向图)的最小路径覆盖 Air Raid

    欢迎参加——BestCoder周年纪念赛(高质量题目+多重奖励) Air Raid Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65 ...

随机推荐

  1. Get Cordova Ready for Grunt and CoffeeScript

    Cordova, Grunt and Coffee You may reference to below if you deside to work with coffee instead of Ja ...

  2. linux编程掌握常用命令

    1)编译应用程序 make -f makefile_5_2 clean make -f makefile_5_2 2)关于共享目录 在linux虚拟机的/mnt/hgfs下可看到该文件夹 3)cd命令 ...

  3. JSP自定义标签——简单标签(1)

    前面一篇博客介绍了自定义标签的传统标签使用方式,但是我们会发现,使用传统标签非常的麻烦,而且接口还多,现在传统标签基本都没用了,除了一些比较久的框架.Sun公司之后推出了一个新的标签使用方式,称之为简 ...

  4. Central Europe Regional Contest 2012 Problem H: Darts

    http://acm.hunnu.edu.cn/online/problem_pdf/CERC2012/H.pdf HUNNU11377 题意:飞镖环有十个环,没个环从外到里对应一个得分1~10,每个 ...

  5. Mysql对自增主键ID进行重新排序

    Mysql数据库表的自增主键ID号经过一段时间的添加与删除之后乱了,需要重新排列. 原理:删除原有的自增ID,重新建立新的自增ID. 1,删除原有主键: ALTER TABLE `table_name ...

  6. JDWP

    JPDA(Java Platform Debugger Architecture) 是 Java 平台调试体系结构的缩写,通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用 ...

  7. address_space 从哪里来

    address_space 从哪里来 这两天想弄清楚linux的内存分配,忽然看到了address_space,就想弄明白. 整个内核就见到 address_space(1)和address_spac ...

  8. C语言数据结构----递归的应用(斐波拉契数列、汉诺塔、strlen的递归算法)

    本节主要说了递归的设计和算法实现,以及递归的基本例程斐波拉契数列.strlen的递归解法.汉诺塔和全排列递归算法. 一.递归的设计和实现 1.递归从实质上是一种数学的解决问题的思维,是一种分而治之的思 ...

  9. 浅解ARC中的 __bridge、__bridge_retained和__bridge_transfer

    文章来源:http://www.outflush.com/2015/03/introduction-of-arc-bridge-type-transfer/ 在对 bridge 相关的修饰符解说前.首 ...

  10. web.xml在&lt;init-param&gt;一个错误

    Description ResourcePathLocationType cvc-complex-type.2.4.a: Invalid content was found starting with ...