捉迷藏

给定一个有向无环图 最多找到多少个点 并且这些点相互不连通

有向无环图的最小路径点覆盖=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;
}

如果要构造方案 从路径终点向起点找 找到路径分叉即可

posted @ 2022-02-11 21:45  __iostream  阅读(30)  评论(0)    收藏  举报