• 【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-MaxMatch());
    	return 0;
    }
  • 相关阅读:
    剑指offer-替换空格
    Python replace方法并不改变原字符串
    退出循环break,在while、for、do...while、循环中使用break语句退出当前循环,直接执行后面的代码。
    do{}while()
    while循环
    for循环
    switch用法
    Javascript获取select下拉框选中的的值
    js关于a++ 与++a
    onload属性使用方法
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4452926.html
Copyright © 2020-2023  润新知