HDOJ-1160-FatMouse's Speed 解题报告

       一道求最长上升子序列的变形题,较简单的动态规划。题意:普遍认为老鼠体重越重的话,行动的速度就越慢,现在在文件中输入每一个老鼠的体重和速度信息,老鼠编号从1开始,要求选出最多的老鼠排成序列,使得老鼠的体重严格递增,速度严格递减,请输出这个序列的老鼠个数以及按顺序输出这个序列的老鼠编号。


       我的解题思路:首先输入中并没有给出老鼠的总数,所以我们要一边输入一边计算老鼠的个数,顺便给每一个老鼠编号。不使用下标来编号的原因是因为接下来要排序。因为有体重和速度两种权,我们先将其中一种权排序,之后就可以直接在另一个权上使用求最长上升子序列的解法了。比如:当我们已经按体重从小到大的顺序给老鼠排好序了,那么我们假设dp[i]表示当编号为i的老鼠为这个序列中最后一个老鼠时,这个序列的最大长度,那么dp[i] = max(dp[j]) + 1,其中(1<=j<i && speed[j] > speed[i])。然后最长的序列长度就是最大的dp,至于按顺序输出老鼠编号序列,还是老方法,在记录dp时顺便存下前一个老鼠的编号,最后从终点往起点记录路径再输出就行了。当然,或者你也可以存下一个老鼠的编号,这样你可以直接从起点输出路径直到终点就ok了(貌似这样更加简单些)。


       我的解题代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <stack>

using namespace std;

#define N 1003

struct mouse
{
    int weight; //体重
    int speed;  //速度
    int id;     //编号
};

struct DP
{
    int pi;     //当构成序列的前一个下标
    int len;    //长度
};

mouse m[N];
DP dp[N];
int n;          //老鼠数量
stack <int> s;  //用于存储编号的栈

void Init();    //初始化

void Read();    //输入

int Mycmp(const void *a, const void *b);    //排序比较函数

void DataProcess();     //数据处理

int main()
{
    Init();
    Read();
    qsort(&m[1], n, sizeof(mouse), Mycmp);
    DataProcess();
    return 0;
}

void Init()
{
    for (int i=0; i<N; ++i)
    {
        dp[i].pi = 0;
    }
    n = 1;
    return;
}

void Read()
{
    while (~scanf("%d %d", &m[n].weight, &m[n].speed))
    {
        m[n].id = n;
        ++n;
    }
    return;
}

int Mycmp(const void *a, const void *b)
{
    if ((*(mouse *)a).weight != (*(mouse *)b).weight)       //优先按照体重排序
    {
        return (*(mouse *)a).weight - (*(mouse *)b).weight;
    }
    return (*(mouse *)b).speed - (*(mouse *)a).speed;
}

void DataProcess()
{
    dp[1].len = 1;
    int anslen = 1;     //构成序列的老鼠个数
    int ansi = 1;       //构成序列的最后一个老鼠的下标
    for (int i=2; i<n; ++i)
    {
        int maxlen = 1;
        int maxi = 0;
        for (int j=i-1; j>0; --j)
        {
            if (dp[j].len >= maxlen && m[j].speed > m[i].speed && m[j].weight < m[i].weight)
            {
                maxlen = dp[j].len + 1;
                maxi = j;
            }
        }
        dp[i].len = maxlen;
        dp[i].pi = maxi;
        if (dp[i].len > anslen)
        {
            anslen = dp[i].len;
            ansi = i;
        }
    }
    printf("%d\n", anslen);
    while (ansi != 0)           //路径存栈
    {
        s.push(m[ansi].id);
        ansi = dp[ansi].pi;
    }
    while (!s.empty())          //输出路径
    {
        printf("%d\n", s.top());
        s.pop();
    }
    return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值