题意
给出点和边,求最少的路径使得可以覆盖所有的点,一种情况是点可以重复,一种是点不可以重复走。
不可重复
#include <string.h>
#include <cstdio>
using namespace std;
#define ll long long
#define maxn 600+66
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define mod 1000000007
#define INF 0x3f3f3f3f
struct Two///路径可以相互交叉,所以就是最小路径覆盖+Warshell传递闭包
{
int G[maxn][maxn];
int match[maxn];
int vis[maxn];
int n,m;
void init(int nn,int mm)
{
n=nn;
m=mm;
memset(G,0,sizeof(G));
}
int dfs(int cur)
{
rep(i,1,m)
{
if(!G[cur][i]||vis[i])
continue;
vis[i]=1;
if(match[i]==-1||dfs(match[i]))
{
match[i]=cur;
return 1;
}
}
return 0;
}
int solve(int n)
{
memset(match, -1, sizeof match);
int ans=0;
rep(i,1,n)
{
memset(vis,0,sizeof(vis));
if(dfs(i))
ans++;
}
return ans;
}
} D;
int main()
{
int n,m;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
D.init(n,n);
rep(i,1,m)
{
int a,b;
scanf("%d %d",&a,&b);
D.G[a][b]=1;
}
int ans=n-D.solve(n);
//cout<<D.solve(n)<<"---"<<endl;;
printf("%d\n",ans);
}
return 0;
}
可以重复
#include <string.h>
#include <cstdio>
using namespace std;
#define ll long long
#define maxn 600+66
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define mod 1000000007
#define INF 0x3f3f3f3f
struct Two///路径可以相互交叉,所以就是最小路径覆盖+Warshell传递闭包
{
int G[maxn][maxn];
int match[maxn];
int vis[maxn];
int n,m;
void init(int nn,int mm)
{
n=nn;
m=mm;
memset(G,0,sizeof(G));
}
int dfs(int cur)
{
rep(i,1,m)
{
if(!G[cur][i]||vis[i])
continue;
vis[i]=1;
if(match[i]==-1||dfs(match[i]))
{
match[i]=cur;
return 1;
}
}
return 0;
}
int solve(int n)
{
memset(match, -1, sizeof match);
int ans=0;
rep(i,1,n)
{
memset(vis,0,sizeof(vis));
if(dfs(i))
ans++;
}
return ans;
}
void floyed()
{
rep(k,1,n)
{
rep(i,1,n)
{
rep(j,1,n)
{
if(G[i][k]+G[k][j]==2)
{
G[i][j]=1;
}
}
}
}
}
} D;
int main()
{
int n,m;
while(scanf("%d %d",&n,&m),n||m)
{
D.init(n,n);
rep(i,1,m)
{
int a,b;
scanf("%d %d",&a,&b);
D.G[a][b]=1;
}
D.floyed();
int ans=n-D.solve(n);
//cout<<D.solve(n)<<"---"<<endl;;
printf("%d\n",ans);
}
return 0;
}