有向无环图(DAG)的最小路径覆盖
2016-05-07 16:09
267 查看
原博地址http://www.cnblogs.com/justPassBy/p/5369930.html
有向无环图(DAG)的最小路径覆盖
DAG的最小路径覆盖
![](http://www.alphaway.org/wp-content/uploads/2016/04/QQ20160408-0.png)
定义:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点。
最小路径覆盖分为最小不相交路径覆盖和最小可相交路径覆盖。
最小不相交路径覆盖:每一条路径经过的顶点各不相同。如图,其最小路径覆盖数为3。即1->3>4,2,5。
最小可相交路径覆盖:每一条路径经过的顶点可以相同。如果其最小路径覆盖数为2。即1->3->4,2->3>5。
特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0。
DAG的最小不相交路径覆盖
算法:把原图的每个点V拆成VxVx和VyVy两个点,如果有一条有向边A->B,那么就加边Ax−>ByAx−>By。这样就得到了一个二分图。那么最小路径覆盖=原图的结点数-新图的最大匹配数。证明:一开始每个点都是独立的为一条路径,总共有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 = 200 + 10;
vector<int> g
;
int cy
;
bool vis
;
bool dfs(int u){
for(int i=0; i<g[u].size(); ++i){
int v = g[u][i];
if(vis[v]) continue;
vis[v] = true;
if(cy[v]==-1 || dfs(cy[v])){
cy[v] = u;
return true;
}
}
return false;
}
int solve(int n){
int ret = 0;
memset(cy, -1, sizeof(cy));
for(int i=1;i<=n;++i){
memset(vis, 0, 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=1;i<=n;++i)
g[i].clear();
for(int i=0;i<m;++i){
scanf("%d%d",&u,&v);
g[u].push_back(v);
}
int ans = solve(n);
printf("%d\n",ans);
}
return 0;
}
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 = 500 + 10; bool dis ; bool vis ; int cy ; void floyd(int n){ for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) for(int k=1;k<=n;++k) if(dis[i][k] && dis[k][j])//传递可达性 dis[i][j] = true; } bool dfs(int u, int n){ for(int i=1;i<=n;++i){ if(!vis[i] && dis[u][i]){ vis[i] = true; if(cy[i]==-1 || dfs(cy[i], n)){ cy[i] = u; return true; } } } return false; } int solve(int n){ int cnt = 0; memset(cy,-1,sizeof(cy)); for(int i=1;i<=n;++i){ memset(vis,0,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=1;i<=n;++i) for(int j=1;j<=n;++j) dis[i][j] = false; for(int i=1;i<=m;++i){ scanf("%d%d",&a,&b); dis[a][b] = true; } floyd(n); int ans = solve(n); printf("%d\n",ans); } return 0; }
相关文章推荐
- 在ASP.NET 2.0中操作数据之二十四:分页和排序报表数据
- high memory 映射 ----2
- 《Apache Cocoon2.2 学习》前言
- Science发表的超赞聚类算法
- 事件绑定1
- Resharp最新破解方法
- Python2 连接MySQL
- EventLog实现事件日志操作
- 数据处理1:一个中型数据的数据处理平台构建
- GridView的用法
- android studio 解决External file changes sync
- JAVA中将一个时间段按固定间隔拆分为List
- keychain service钥匙串服务
- Mac Linux Maven环境变量设置
- GreenDao 使用教程 一
- HTML的title属性
- volatile关键字与竞态条件和sigchild信号
- Elasticsearch 常用的java操作
- 龙书D3D11章节习题答案(第七章)
- Activity生命周期详细分析