• [BZOJ1143][CTSC2008]祭祀river(Dilworth定理+二分图匹配)


    题意:给你一张n个点的DAG,最大化选择的点数,是点之间两两不可达。

    要从Dilworth定理说起。

    Dilworth定理是定义在偏序集上的,也可以从图论的角度解释。偏序集中两个元素能比较大小,则在图中连一条有向边。

    定义反链为一个点集,满足集合中的点两两不可达。

    Dilworth定理:最小路径覆盖=最长反链。

    证明:http://vfleaking.blog.163.com/blog/static/1748076342012918105514527/

    例子:NOIP1999第二问:给定一个数列a,将其分成若干个子序列,使每个子序列都是下降子序列,并最小化分的子序列个数。

    对于所有i<j且a[i]>a[j],从i向j连边,则问题转化成求图的最小路径覆盖,根据Dilworth定理进一步转化为求最长反链,而这里的最长反链即是最长不降子序列的长度。所以这题只要求一个最长不降子序列即可。

    回到这道题,就是要求一个最长反链。这里任意两个可达的点之间都需要连一条边,所以需要求传递闭包。

    然后通过Dilworth定理转化为求DAG的最小路径覆盖,这就是二分图匹配的经典问题了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=110;
     8 int n,m,u,v,ans,lk[N];
     9 bool mp[N][N],a[N][N],vis[N];
    10 
    11 bool find(int x){
    12     rep(i,1,n) if (!vis[i] && mp[x][i]){
    13         vis[i]=1;
    14         if (!lk[i] || find(lk[i])) { lk[i]=x; return 1; }
    15     }
    16     return 0;
    17 }
    18 
    19 int main(){
    20     freopen("bzoj1143.in","r",stdin);
    21     freopen("bzoj1143.out","w",stdout);
    22     scanf("%d%d",&n,&m);
    23     rep(i,1,m) scanf("%d%d",&u,&v),mp[u][v]=1;
    24     rep(k,1,n) rep(i,1,n) rep(j,1,n) mp[i][j]|=mp[i][k]&mp[k][j];
    25     rep(i,1,n) rep(j,1,n) if (i!=j && mp[i][j]) a[i][j]=1;
    26     rep(i,1,n){
    27         memset(vis,0,sizeof(vis));
    28         if (find(i)) ans++;
    29     }
    30     printf("%d
    ",n-ans);
    31     return 0;
    32 }
  • 相关阅读:
    Importing multi-valued field into Solr from mySQL using Solr Data Import Handler
    VMware Workstation 虚拟机使用无线wifi上网配置
    Linux开发黑客
    GitHub 使用说明
    虹软人脸检测和识别C#
    C#将结构体和指针互转的方法
    笔记本电脑连接wifi,同时提供热点wifi给手机使用
    基于STM32L4的开源NBIOT开发资料
    ESP8266擦除工具完整安装
    开发快平台(M302I小e开发板系列教程)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9309332.html
Copyright © 2020-2023  润新知