zoukankan      html  css  js  c++  java
  • [BZOJ 1143] 祭祀river

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1143

    Solution:

    一道最长反链的模板题

    由Dilworth定理可知:最小链覆盖数(偏序集能划分成的最少的全序集的个数) = 最长反链长度

    其对偶定理:最长链长度 = 最小反链覆盖数

    (VFleaking的证明:http://vfleaking.blog.163.com/blog/static/1748076342012918105514527/)

    求解最小链覆盖的方式:

    1、先用Floyd求出传递闭包,表示哪些(x,y)间是可以相互抵达的

    2、将每个点拆分,最小链覆盖=n-二分图最大匹配

    证明:每匹配两个点,则意味着少了一条链,从而最少链的数量为n-最大匹配的数量

    而先计算传递闭包是为了实现路径的可交叉,相当于“跳过”交叉点进行匹配

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int MAXN=105;
    int n,m,x,y,match[MAXN*2],f[MAXN][MAXN],vis[MAXN*2];
    
    bool dfs(int x)
    {
        for(int i=1;i<=n;i++)
            if(f[x][i] && !vis[i])
            {
                vis[i]=true;
                if(match[i]==-1 || dfs(match[i]))
                {
                    match[i]=x;
                    return true;
                }
            }
        return false;
    }
    
    int main()
    {
        cin >> n >> m;
        for(int i=1;i<=m;i++)
            cin >> x >> y,f[x][y]=1;
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    f[i][j]|=f[i][k]&&f[k][j]&&!(i==j);
        
        memset(match,-1,sizeof(match));
        int res=n;
        for(int i=1;i<=n;i++)
            memset(vis,0,sizeof(vis)),res-=dfs(i);
        for(int i=1;i<=n;i++) cout << match[i] << " ";
        cout << endl;
        cout << res;
        return 0;
    }

    Review:

    1、最小链覆盖(交叉/不交叉)的求法

    2、记住将i=j的f[i][j]设为0

  • 相关阅读:
    112th LeetCode Weekly Contest Validate Stack Sequences
    112th LeetCode Weekly Contest Minimum Increment to Make Array Unique
    C# 有关系统音量的操作
    C# 关于时区的操作
    WordPress 设置GeoIP数据库目录权限时错误解决方案
    AtCoder Beginner Contest 113 C
    AtCoder Beginner Contest 113 B
    AtCoder Beginner Contest 113 A
    将Tomcat注册为Windows服务
    常用的调试方法
  • 原文地址:https://www.cnblogs.com/newera/p/9095147.html
Copyright © 2011-2022 走看看