Description
定义: 一个不含圈的有向图G中,G的一个路径覆盖是一个其结点不相交的路径集合P,图中的每一个结点仅包含于P中的某一条路径。路径可以从任意结点开始和结束,且长度也为任意值,包括0。请你求任意一个不含圈的有向图G的最小路径覆盖数。
提示:最小路径覆盖数=G的定点数-最小路径覆盖中的边数
最小路径覆盖数=原图G的顶点数-二分图的最大匹配数
Input
t 表示有t组数据;n 表示n个顶点(n<=120);m 表示有m条边;
接下来m行,每行有两个数 i,j表示一条有向边。
Output
最小路径覆盖数
Sample Input
2
4
3
3 4
1 3
2 3
3
3
1 3
1 2
2 3
Sample Output
2
1
分析
什么是有向图G的最小路径覆盖?
首先,图G必须是有向无环的。路径覆盖就是在图G中找出一些路径,每条路径从起点走到终点并且标记中间经过的点。最后,每个点只被标记一次。选出的这些路径组成路径覆盖。如果找出最少的路径成为一个路径覆盖,则称为最小路径覆盖。
最小路径覆盖数=原图的顶点数-二分图的最大匹配数
所以输入后直接连边跑匈牙利算法,求出最大匹配,然后用顶点数减去最大匹配即可出答案。
注意多组数据数组清零,变量初始化。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
int ans,tot,t,n,m,link[100001],cover[100001],hd[100001];
struct node
{
int to,next;
}a[100001];
void add(int x,int y)
{
a[++tot]=(node){y,hd[x]};
hd[x]=tot;
}
bool find(int x)
{
for(int i=hd[x];i>0;i=a[i].next)
{
int j=a[i].to;
if(cover[j]==0)
{
cover[j]=1;
int q=link[j];
link[j]=x;
if(q==0||find(q))
{
return true;
}
link[j]=q;
}
}
return false;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
add(x,y);
}
for(int i=1;i<=n;i++)
{
memset(cover,0,sizeof(cover));
find(i);
}
for(int i=1;i<=n;i++)
{
if(link[i]!=0)
{
ans++;
}
}
cout<<n-ans<<endl;//最小路径覆盖数=原图的顶点数-二分图的最大匹配数
memset(link,0,sizeof(link));
memset(hd,0,sizeof(hd));
tot=0;
ans=0;
}
return 0;
}