【动态规划】【Dilworth定理】AOJ 0033 Ball #挑战程序设计竞赛

题目大意

有n个序列,每个序列长度都是10且每个序列中元素互不相同,简单记录为

x 1 , x 2 , . . . , x 10 x_1,x_2,...,x_{10} x1,x2,...,x10

问每个序列可不可以划分这样两个集合,其中每个集合中任意两个元素都满足

x i < x j & & i < j x_i < x_j \quad \&\&\quad i < j xi<xj&&i<j

对每个序列,可以按照上述条件划分,则输出YES,否则输出NO。

每个集合中任意两个元素都是可比的,这自然让我们想到偏序集的概念,而给定的条件正是一个构成偏序集的条件。这个题在问我们原集合可不可以划分为两个链。链是一个集合,其中任意两个元素都可比。而划分的意思是者两个链相交为空,相并为原集。

那我们如何判断这个集合可不可以划分为2个链呢?这时就要请出我们的Dilworth定理了。它是解决偏序集中链与反链极值问题的利器。反链也是一个集合,它的定义是,其中的任意两个元素都不可比。Dilworth定理的表述如下:

对偏序集(X, ≤ \le ),如果

  • 可找到的最长链的长度为 r r r,那么这个集合可以划分出 r r r条反链且不能再少。
  • 可找到的最长反链的长度为 l l l, 那么这个集合可以划分出 l l l条链且不能再少。

所以要判断原集合如果拥有一条长度大于2的反链,它就必定不能被划分为2条链。那么我们如何知道有没有长度大于2的反链呢?只需要看看它最长的那个反链。这是我的思考顺序,可能有些别扭哈。

观察反链的结构,把它们按照脚标顺序由小到大排列,为了不可比,脚标小的值就大,故我们要求的东西就很清楚了,就是原序列的最长下降子序列。注意读题时要认真,要抓住序列中两两不同的特点观察集合的特征。

求最长下降子序列就没什么好说的了,动态规划求就好了。不再赘述。

另外,在《挑战程序设计竞赛》中,这道题应该是用深搜做的,因为只有10个数,剪剪枝就差不多了。

源码如下:

//Dilworth 
#include
#include
#include
using namespace std;
int n, max_len;
int num[11], dp[11];

int main(){
    //freopen("in.txt", "r", stdin);
    scanf("%d", &n);
    while(n--){
        for(int i=0; i<10; i++){
            scanf("%d", &num[i]);
        }
        memset(dp, 0, sizeof(dp));
        max_len = 1;
        dp[0] = 1;
        
        for(int i=1; i<10; i++){
            for(int j=0; j 2)
            printf("NO\n");
        else 
            printf("YES\n");
    }
    return 0;
}

你可能感兴趣的:(算法习题,原创,组合数学,动态规划,算法,挑战程序设计竞赛,OI)