题目
定义: 一个不含圈的有向图G中,G的一个路径覆盖是一个其结点不相交的路径集合P,图中的每一个结点仅包含于P中的某一条路径。路径可以从任意结点开始和结束,且长度也为任意值,包括0。请你求任意一个不含圈的有向图G的最小路径覆盖数。
提示:最小路径覆盖数=G的定点数-最小路径覆盖中的边数
最小路径覆盖数=原图G的顶点数-二分图的最大匹配数
题解
把原图的每个点拆成两个点,然后从有向边的起点向终点连线,其中起点全部放在二分图的同一边。
这时可以把n个点看成独立的一个路径,然后选择一个匹配就是把两个路径连起来。可以看出同一个起点不能连出两条匹配,因为同一条路径方向不能改变,同理同一个终点也是这样,符合匹配的定义。
最后答案=顶点数-最大匹配数
时间复杂度 O ( n 3 ) O(n^3) O(n3)
代码
#include <cstdio>
#include <cstring>
using namespace std;
int t,n,m,cnt;
int ls[150],ne[20005],y[20005],link[150];
bool cover[150];
bool dfs(int k){
for (int i=ls[k];i;i=ne[i])
if (!cover[y[i]]){
int t=link[y[i]];
link[y[i]]=k;
cover[y[i]]=1;
if (t==0||dfs(t)) return 1;
link[y[i]]=t;
}
return 0;
}
int main(){
scanf("%d",&t);
for (;t;t--){
scanf("%d",&n);
scanf("%d",&m);
cnt=0;
memset(link,0,sizeof(int)*(n+3));
memset(ls,0,sizeof(int)*(n+3));
for (int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
ne[++cnt]=ls[a];ls[a]=cnt;y[cnt]=b;
}
int ans=n;
for (int i=1;i<=n;i++){
memset(cover,0,sizeof(bool)*(n+3));
if (dfs(i)) ans--;
}
printf("%d\n",ans);
}
}