poj 1065 Wooden Sticks

/*
 *  poj 1064 Wooden Sticks

    题目大意:
        给定一系列木棍,每个木棍有两个属性长度l和重量w,这些木棍要放到某台机器中进行处理。
        机器处理每个木棍前有一段时间的做准备工作,其规则如下:

        1)处理第一条木棍前准备时间为1
        2)如果后面处理的木棍的属性满足l'>l并且w'>w则无需准备,否则需要时间为1的准备

        现在需要你编写程序,给出指定输入的木棍需要的最少准备时间值。

    解题思路:
        1、将所有木棍按照其中一个属性从小到大排序,这里选择属性l
        2、求解排序后的序列中w属性的最长严格下降子序列的长度

    数学模型: 
        LDS -- 最长严格下降子序列长度

        f(i)表示以i个元素为尾的最长严格下降子序列的长度,则有如下递归式成立:

            f(i) = max{f(k) | k<i 并且 a[k]>a[i]} + 1

    正确性证明:

        假设排序后的木棍如下:

        i|  1   2   3 | 4   5   6   7 | 8   9
        -|------------|---------------|-------
        l|  1   2   3 | 4   5   6   7 | 8   9
         |            |               |
        w|  a   b   f | c   d   e   i | g   h   

        本例所需准备时间是2 -- 最长严格下降子序列的长度,具体排列如下:

        i|  1   2   3   4   5   6 | 7   8   9
        -|------------------------|-----------
        l|  1   2   4   5   6   7 | 3   8   9
         |                        |
        w|  a   b   c   d   e   i | f   g   h  
*/

#include <iostream>
#include <cstdio>
#include <cstdlib>

namespace {
    using namespace std;

    typedef struct STICK
    {
        int l, w; 
    }STICK_S;

    int stick_cmp(const void *pOP1, const void *pOP2)
    {
        STICK_S *ps1 = (STICK_S *)pOP1;
        STICK_S *ps2 = (STICK_S *)pOP2;

        if (ps1->l < ps2->l)  return -1;
        
        /* 
            注意,如果属性1相同的话,还需要按照属性2的大小排序
            这是因为,最长下降子序列长度取决于元素的排列
        */
        if (ps1->l == ps2->l) 
        {
            if (ps1->w < ps2->w) return -1;
            if (ps1->w == ps2->w) return 0;
            if (ps1->w > ps2->w) return 1;
        }
        
        if (ps1->l > ps2->l)  return  1;
    }

    const int N_MAX = 5000;
    STICK_S sticks[N_MAX];
    int f[N_MAX];

    int n;
    int wooden_sticks()
    {
        qsort(sticks, n, sizeof(sticks[0]), stick_cmp);
        
        int t=1;
        for (int i=0; i<n; i++)
        {
            f[i] = 1; // 初始化
            for (int j=0; j<i; j++)
            {
                if (sticks[j].w>sticks[i].w && (f[j]+1)>f[i])
                    f[i] = f[j]+1; // 更新f[i]
            }

            if (f[i]>t) t=f[i]; // 更新最大长度
        }

        return t;
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    for (int t=0; t<T; t++ )
    {
        scanf("%d", &n);
        for (int i=0; i<n; i++)
        {
            scanf("%d%d", &sticks[i].l, &sticks[i].w);
        }

        printf("%d\n", wooden_sticks());
    }
    
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值