zoukankan      html  css  js  c++  java
  • 【洛谷4298】[CTSC2008] 祭祀(Dilworth定理+二分图匹配)

    点此看题面

    • 给定一张(n)个点(m)条边的(DAG),求最多能选出多少个点,使得两两无法到达。
    • 进一步,给出任意一组最优构造方案,并询问每个点是否可能出现在一组最优构造方案中。
    • (nle100,mle1000)

    (Dilworth)定理

    精简概括:对于任意有限偏序集,最大反链长等于最小链划分

    其中,指的是一串元素(x_{1sim n})满足(x_1le x_2le...le n)(le)为这个偏序集中的偏序关系。

    反链指的是一堆元素(x_{1sim n}),它们两两之间无法比较。

    二分图匹配解最小路径覆盖

    对于这道题,这个偏序关系可以定义为:(xle y)当且仅当(x)能到达(y)。(可以(Floyd)预处理出)

    然后发现题目要求的就是最大反链长,那就可以转化为最小链覆盖,放在这题中就变成了最小路径覆盖

    经典的二分图匹配问题,把每个点视作一个出点和一个入点,对于一条边(x ightarrow y)(x)的出点向(y)的入点连边。

    答案上界是点数,而每匹配成功一条边就可以少用一条链,因此答案就是点数-二分图最大匹配

    能否出现在最优构造方案中

    发现这里的反链其实等价于独立集

    所以判断一个点能否出现在最优构造方案中,只要删去它及其相邻点,然后用之前的方法跑一遍看看新的最大反链长是否恰好比原先小(1),是则能够出现在最优构造方案中。

    而要给出一组最优构造方案,只要连续使用上面的结论,每确定一个点可能出现在最优构造方案中将它选中,保留它产生的影响(即删去它的相邻点)继续枚举。

    代码:(O(n^4))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100
    #define M 1000
    using namespace std;
    int n,m;bitset<N+5> f[N+5];
    int p[N+5],s[N+5],vis[N+5];I bool Match(CI x,CI ti)//二分图匹配
    {
    	for(RI i=1;i<=n;++i) if(f[x].test(i)&&
    		!p[i]&&vis[i]^ti&&(vis[i]=ti,!s[i]||Match(s[i],ti))) return s[i]=x;
    	return 0;
    }
    I int Calc() {RI i;for(i=1;i<=n;++i) s[i]=vis[i]=0;//清空
    	RI t=0;for(i=1;i<=n;++i) !p[i]&&(t+=!Match(i,i));return t;}//点数-二分图最大匹配,即匹配失败点数
    int main()
    {
    	RI i,j,x,y;for(scanf("%d%d",&n,&m),i=1;i<=m;++i) scanf("%d%d",&x,&y),f[x].set(y);
    	for(j=1;j<=n;++j) for(i=1;i<=n;++i) f[i].test(j)&&(f[i]|=f[j],0);//Floyd
    	RI k=Calc(),t=k;for(printf("%d
    ",k),i=1;i<=n;++i)
    	{
    		if(p[i]) {putchar('0');continue;}//如果已经被删掉
    		for(j=1;j<=n;++j) p[j]+=i==j||f[j][i]||f[i][j];if(Calc()==t-1) {--t,putchar('1');continue;}//如果在最优构造方案中就选中
    		for(j=1;j<=n;++j) p[j]-=i==j||f[j][i]||f[i][j];putchar('0');//没选中就撤销影响
    	}
    	for(putchar('
    '),i=1;i<=n;++i)
    	{
    		for(j=1;j<=n;++j) p[j]=i==j||f[j][i]||f[i][j];putchar(48|(Calc()==k-1));//独立判断是否能在最优构造方案中
    	}return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    移植Valgrind检测Android JNI内存泄漏
    【转】线性回归最小二乘法和梯度下降法
    【转】成为一名推荐系统工程师永远都不晚
    vue-element-admin使用常见问题
    SpringBoot中如何使用jpa和jpa的相关知识总结
    SpringBoot Controller接收参数的几种常用方式
    java项目其他基础配置
    eclipse 新建 maven 项目 + 消除错误
    vue城市三级联动组件 vue-area-linkage
    Vue中watch的简单应用
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4298.html
Copyright © 2011-2022 走看看