捉迷藏
给定一个有向无环图 最多找到多少个点 并且这些点相互不连通
有向无环图的最小路径点覆盖=n-拆点二分图的最大匹配(路径不能相交)
每个左部点的失配代表该点没有出边 所以代表着一条路径的终点 终点最少,失配点最少,路径覆盖就最少
最小可重点覆盖(路径可以相交)
先传递闭包 再最小点覆盖
d[i][i]的赋值应该根据实际意义( 本身d[i][i]是否赋值不影响其他关系的推出)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
const int N=205;
const int M=30005;
int read()
{
int x=0,f=0,c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return f?-x:x;
}
bool mp[N][N],vis[N];
int match[N];
int n,m;
bool dfs(int x)
{
for(int y=1;y<=n;y++)
{
if(!mp[x][y]||vis[y]) continue; vis[y]=1;
if(!match[y]||dfs(match[y])) { match[y]=x; return true;}
}
return false;
}
int main()
{
n=read(); m=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
mp[x][y]=1;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
mp[i][j]|=mp[i][k]&mp[k][j];
int ans=n;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof vis);
ans-=dfs(i);
}
printf("%d",ans);
return 0;
}
如果要构造方案 从路径终点向起点找 找到路径分叉即可

浙公网安备 33010602011771号