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

而最小路径覆盖又分为:最小不相交路径覆盖最小可相交路径覆盖。

最小不相交路径覆盖 : 就是我们找到的每条路径不能相交,就是每条路径不能有同一个点。
最小可相交路径覆盖 : 这个与上面相对应,就是可以相交。

注意:每个点被自己覆盖,路径长度为0


求解最小不相交路径覆盖: 我们把每个点都拆成两个点,分为入点和出点,如果 u 到 v 有边,那么我们就让 u 的入点连向 v 的出点 , 最后跑一下最大流或者匈牙利 算出最大匹配。答案就是 点的数目 - 最大匹配数

求解最小可相交路径覆盖: 和上面很相似,但是我们再跑最大匹配时,我们先对原图进行一次闭包传递(通过Warshell传递闭包算法),然后过程就一样了。


最小不相交路径覆盖题目:POJ - 1422

AC代码:

#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#define int long long
using namespace std;
const int N=250;
int T,n,m,mat[N],vis[N],res;
int head[N],nex[N*N],to[N*N],tot;
void add(int a,int b){
	to[++tot]=b; nex[tot]=head[a]; head[a]=tot; 
}
bool find(int x,int id){
	for(int i=head[x];i;i=nex[i]){
		if(vis[to[i]]!=id){
			vis[to[i]]=id;
			if(!mat[to[i]]||find(mat[to[i]],id)){
				mat[to[i]]=x;	return 1;
			}
		}
	}
	return 0;
}
signed main(){
	cin>>T;
	while(T--){
		memset(head,0,sizeof head);	res=tot=0;
		memset(mat,0,sizeof mat);	memset(vis,0,sizeof vis);	
		cin>>n>>m;
		while(m--){
			int a,b;	cin>>a>>b;	add(a,b);
		}
		for(int i=1;i<=n;i++)	res+=find(i,i);
		cout<<n-res<<endl;
	}
	return 0;
}

最小可相交路径覆盖题目:POJ - 2594

AC代码:

#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#define int long long
using namespace std;
const int N=510;
int n,m,mat[N],vis[N],g[N][N],res;
void Warshell(){
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if(g[i][k]&&g[k][j])	g[i][j]=1;
}
bool find(int x,int id){
	for(int i=1;i<=n;i++){
		if(g[x][i]&&vis[i]!=id){
			vis[i]=id;
			if(!mat[i]||find(mat[i],id)){
				mat[i]=x;	return 1;
			}
		}
	}
	return 0;
}
signed main(){
	while(cin>>n>>m,n||m){
		memset(g,0,sizeof g);	memset(vis,0,sizeof vis);
		memset(mat,0,sizeof mat);	res=0;
		while(m--){
			int a,b;	cin>>a>>b;	g[a][b]=1;
		}
		Warshell();
		for(int i=1;i<=n;i++)	res+=find(i,i);
		cout<<n-res<<endl;
	}
	return 0;
}