poj1065

来源:互联网 发布:广州恒大淘宝 编辑:程序博客网 时间:2024/06/06 03:18
写了下DP里的poj1065,发现并没有搞懂最好的解法,解法如下(以后在学吧),自己的贪心O(N2)也水过.

题目的确需要稍加思考,这道题的要求其实是将所有stick分为x个不下降子序列( Ai <= Ai+1 ),然后问题归结于求x的最小值。

x的最小值其实等于按l递增排序后stick按w最长下降子序列的长度L,证明如下:

若x < L,先从stick中取出最长下降子序列L,取走的元素留下一个大小相同的“空穴”,然后将剩下的元素和空穴分成x个不下降子序列。接着把最长下降子序列L中的L个元素放回这L个空穴里。由于x < L,所以根据鸽笼原理,必然有两个或两个以上的下降子序列L中的元素(b > a)被按顺序放到同一个不下降子序列(a <= b),产生矛盾(两者本应该是等效的)     #include <iostream>

#include <algorithm>#include <vector>#include <iterator>#include <cstring>using namespace std;struct wood{    int l,w;    wood () {}    wood (int a,int b) : l(a),w(b) {}    bool operator < (const wood & a) const {        return l == a.l ? w < a.w : l < a.l;    }}a[5010];bool vis[5010];int main(){    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);    int T;    cin >> T;    while(T --) {        int n;        cin >> n;        int l,w;        for(int i = 0;i < n;i ++) {            cin >> a[i].l >> a[i].w;        }        sort(a,a+n);        memset(vis,0,sizeof(vis));        int ans = 0;        for(int i = 0;i < n;i ++) {            if(!vis[i]) {                vis[i] = 1;                int now = a[i].w;                for(int j = i + 1;j < n;j ++) {                    if(!vis[j] && a[j].w >= now) {                        vis[j] = 1;                        now = a[j].w;                    }                }                ans ++;            }        }        cout << ans << endl;    }    return 0;}


原创粉丝点击