POJ 1065-Wooden Sticks [dp+Dilworth定理] 《挑战程序设计竞赛》2.3

来源:互联网 发布:周易取名 知乎 编辑:程序博客网 时间:2024/05/21 14:56

题目链接 POJ 1065-Wooden Sticks
题目大意

n 块木板, 每块都有各自的长l和宽w
在加木板的时候,刚刚加工了一块长和宽分别为lw,加工的下一块长l,宽w, 如果l<=l 并且w<=w, 则可以直接加工,否则需要花费1单位时间来重新设置机器。加工第一块木板的时候必须设置机器。
求加工完n 块木板所需要的最短的重置机器所花费的时间。

输入格式:

多组输入, 第一行表示测试数据的组数
接下来2行一组, 每组第一行为木板数, 第二行为l1,w1,...ln,wn

输出格式:

每组一行, 一个数字,表示最短的重置机器所花费的时间

题解:

将木板按照长来排序, 比如 ( 9 , 4 ) , ( 2 , 5 ) , ( 1 , 2 ) , ( 5 , 3 ) , ( 4 , 1 )
排序后为 ( 1 , 4 ) , ( 2 , 1 ) , ( 3 , 5 ) , ( 4 , 9 ) , ( 5 , 2 )
然后再找按照宽度wi , 将上面的序列分成x 个不下降的子序列。
比如 ( 1 , 4 ) , ( 3 , 5 ) , ( 4 , 9 ) 为一组, ( 2 , 1 ) , ( 5 , 2 ) 为一组, x=2
本题要求的答案就是x 的最小值
根据Dilworth定理, 最小的不降序列的个数等于最长的下降序列的长度,所以这题只需要把木板按照长度排序, 然后再找宽度的最长下降子序列的长度。这里用了《挑战程序设计竞赛》里的二分的算法, 复杂度为O(nlogn), 朴素的动态规划需要O(n2)
非常巧妙的利用二分的算法。。最近时间紧, 日后补上详细讲解

这题和以前做过的“导弹拦截”一样, 都用到了Dilworth定理。以前还推导过定理证明, 理解了好长时间。现在只记得定理的结论了。日后有空把定理的证明补上。
另外还有其他的证明方法, 参考: hankcs码农场

代码:

#include <iostream>#include <algorithm>#define MAXN 5010#define INF 0x3f3f3f3fusing namespace std;typedef pair<int, int> Pair;Pair p[MAXN];int f[MAXN], ans;int n;int main() {    int T;    cin >> T;     for (int t = 0; t < T; t++) {        cin >> n;        for (int i = 0; i < n; i++)             cin >> p[i].first >> p[i].second;        sort(p, p+n);        fill(f, f+n, INF);        for (int i = n-1; i >= 0; i--) {            *lower_bound(f, f+n, p[i].second) = p[i].second;        }        cout << (lower_bound(f, f+n, INF) - f) << endl;    }    return 0;} 
0 0
原创粉丝点击