定义:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点。
最小路径覆盖分为最小不相交路径覆盖和最小可相交路径覆盖。
最小不相交路径覆盖:每一条路径经过的顶点各不相同。如图,其最小路径覆盖数为3。即1->3>4,2,5。
最小可相交路径覆盖:每一条路径经过的顶点可以相同。如果其最小路径覆盖数为2。即1->3->4,2->3>5。
特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0。
DAG的最小不相交路径覆盖
算法:把原图的每个点V拆成Ax−>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[N]; int cy[N]; bool vis[N]; 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; }