【Floyd】【Dilworth定理】【最小路径覆盖】【匈牙利算法】bzoj1143 [CTSC2008]祭祀river

Dilworth定理,将最长反链转化为最小链覆盖。//貌似还能把最长上升子序列转化为不上升子序列的个数?

floyd传递闭包,将可以重叠的最小链覆盖转化成不可重叠的最小路径覆盖(引用:这样其实就是相当于将原图改造了一下,只要 x 能到达 y ,就直接连一条边 (x, y),这样就可以“绕过”原图的一些被其他路径占用的点,直接构造新路径了。)

建立二分图,跑匈牙利。(见白书P357)

#include<cstdio>
#include<cstring>
using namespace std;
#define N 101
#define M 10001
int n,m;
int v[M],next[M],first[N<<1],en;
int mat[N<<1];
bool vis[N<<1],a[N][N];
void AddEdge(int U,int V)
{
	v[++en]=V;
	next[en]=first[U];
	first[U]=en;
}
bool dfs(int U)
{
	for(int i=first[U];i;i=next[i])
	  if(!vis[v[i]])
	    {
	      vis[v[i]]=1;
	      if(mat[v[i]]==-1||dfs(mat[v[i]]))
	        {
	          mat[v[i]]=U;
	          return 1;
	        }
	    }
	return 0;
}
int MaxMatch()
{
	int res=0;
	memset(mat+1+n,-1,sizeof(int)*n);
	for(int i=1;i<=n;++i)
	  {
	  	memset(vis+n+1,0,sizeof(bool)*n);
	  	if(dfs(i)) ++res;
	  }
	return res;
}
int main()
{
	scanf("%d%d",&n,&m);
	int x,y;
	for(int i=1;i<=m;++i)
	  {
	  	scanf("%d%d",&x,&y);
	  	a[x][y]=1;
	  }
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    for(int k=1;k<=n;++k)
	      if(i!=j&&j!=k&&a[j][i]&&a[i][k]) 
	        a[j][k]=1;
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    if(a[i][j])
		  AddEdge(i,j+n); 
	printf("%d\n",n-MaxMatch());
	return 0;
}
posted @ 2015-04-24 11:23  AutSky_JadeK  阅读(290)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト