poj1065--Wooden 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;
}

 

posted @ 2013-03-31 05:12  ttang  阅读(2409)  评论(0编辑  收藏  举报