• poj1065Wooden Sticks利用Dilworth定理


    http://poj.org/problem?id=1065

      这个题目定义了一种偏序关系≤

      (L1, W1)≤(L2, W2)当且仅当L1<=L2且W1<=W2

      给的输入就是一个偏序集,目标就是把这个偏序集划分为一系列chain,并要求chain的个数尽可能少

      根据Dilworth定理,最少的chain个数等于最大的antichain的大小(相关内容参考我的上一篇博文

      如何求最大的antichain的大小呢?

    可以首先考虑antichain具有的性质:

    (1)对antichain中任意两点P(L1, W1)和Q(L2, W2),L1不等于L2(否则P和Q就是可比较的,违反反链性质),W1不等于W2

    (2)如果将反链中的点按照L值从小到大排列,那么W是递减的(考察任意两个相邻的点P(L1, W1)和Q(L2, W2),假设他们违反了递减性质,即W1<=W2,那么P和Q就是可比较的,违反了反链性质)

    考虑到这两点,可以先对所有点按照L值从小到大排列,如果L值相同,W值小的在前(至于为什么W值小的在前,后面解释)

      最长反链就是在这个序列中取一个最长的子序列,要求W值是递减的——这就是最长递减子序列问题了,可以用动态规划在O(n^2)时间内解决。

      之所以排序时,L值相同时,要求W值小的在前,是因为这样就可以简单地归结为最长递减子序列问题,比如最简单的两个点的情况,P(2,3), Q(2,4),那么P应该在Q之前。如果Q在P之前,求最长递减子序列时会得到(2,4)(2,3),这就不是最长反链了

    代码如下:

    #include <stdio.h>
    #include <vector>
    #include <algorithm>
    using namespace std;
    //思想是:按x增序排序,如果x相同,按y增序排序,然后在y序列中
    //找最长递减(不可以相等)子序列
    //因为我要找maximum anti-chain,当x相同时,肯定是可比较的,所以此时必须
    //按照y的增序排序,这样就不会出现选出"x相同,y递减"的point
    //如(2,4),(2,3),保证对一个特定的x,只选一个y
    //sort increasingly by x   1 2 2 3 4
    //y should be increasing   2 3 4 2 1
    //not decreasing           2 4 3 2 1
    class Point {
    public:
        Point (int len, int w){
            this->len = len;
            this->w = w;
        }
    //private:
        int len, w;
    };
    bool operator<(const Point &n1, const Point &n2)
    {
        return n1.len < n2.len || n1.len == n2.len && n1.w < n2.w;
    }
    
    int maxDecreaseLen(vector<Point>& vec){
        int len = vec.size();
        int x[len];//x[i]存储以vec[i]结尾的最长递减子序列长度
        int max = 0;
        for (int i = 0; i < len; i++) {//update x[i] one by one
            x[i] = 1;
            for (int j = 0; j < i; j++) {
                if (x[i] <= x[j] && vec[j].w > vec[i].w) {//...j.....i
                    x[i] = x[j] + 1;
                }
            }
            if (max < x[i]) {
                max = x[i];
            }
        }
        return max;
    
    }
    int main(int argc, const char *argv[])
    {
        int T, n;
        vector<Point> vec;
        scanf("%d", &T);
        while (T--) {
            scanf("%d", &n);
            vec.reserve(n);
            int x, y;
            for (int i = 0; i < n; i++) {
                scanf("%d%d", &x, &y);
                vec.push_back(Point(x, y));
            }
            sort(vec.begin(), vec.end());
            printf("%d\n",maxDecreaseLen(vec));
            vec.clear();
        }
        return 0;
    }
  • 相关阅读:
    CodeForces 980 E The Number Games
    CodeForces 980 D Perfect Groups
    【动态规划】The Triangle
    【动态规划】矩形嵌套
    金块问题-排序-找最大最小
    猪八戒吃西瓜(wmelon)-排序-查找
    【贪心】取数游戏
    【贪心】排队接水
    桐桐的贸易--WA
    【贪心】智力大冲浪
  • 原文地址:https://www.cnblogs.com/fstang/p/2991255.html
Copyright © 2020-2023  润新知