题意: 机器人,探索火星,有n个点,m条边, 边 u->v 为有向边,询问最少派多少机器人可以探索n个点
思路: 与无向图不同的是: 无向图每个匹配的点只能有一个入度 和一个出度 ,但是 在:
1->3 2->3 3->4 3->5 这种情况下,点3 是可以多次经过的,也就是说 3 可以有多个入度出度。
在这种情况下,我们只需要将 1->3->4 2->3->5 看成两条路径。接下来就是如何把3的影响消除:
通过floyd 求传递闭包 可以表示1->4有边 2->5有边。这样一来我们便可以用匈牙利算法来求解。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include <vector>
#include<algorithm>
using namespace std;
const int maxn=1505;
int n,m;
int g[maxn][maxn];
int pre[maxn];//保存各点的匹配点
int vis[maxn];
//vector<int> vec[maxn];
int find(int u)//判断是否存在增广路,存在返回1
{
for(int i=1;i<=n;i++)
{
if(!g[u][i]||vis[i])continue;
vis[i]=1;
if(pre[i]==-1||find(pre[i]))//-1找到未盖点,find是增广路。
{
pre[i]=u;//匹配边和非匹配边交换
return 1;
}
}
return 0;
}
void floyd()
{
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(g[i][j]==0)
if(g[i][k]==1&&g[k][j]==1)
g[i][j]=1;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
memset(pre,-1,sizeof(pre));
memset(g,0,sizeof(g));
int u,v,ans=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
g[u][v]=1;
}
floyd();
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
ans+=find(i);
}
printf("%d\n",n-ans);
}
return 0;
}