一、概述

1. 问题描述

许多大老鼠在讨论一个问题:是不是咱们越胖跑得越快呢?现在需要我们去否定这个思想,给出n个老鼠的体重和速度,需要找出这样的一个老鼠序列:体重递增而速度递减,要求找到最长的序列来否定老鼠的猜想!

2. 问题链接

HDU -- FatMouse's Speed(ACM Step: 3.2.4)

3. 问题截图

HDU -- FatMouse's Speed(ACM Step: 3.2.4)-LMLPHP

图1.1  问题截图

二、算法思路

由于ACM Step3.2系列都是动态规划相关的问题,所以不自觉的就往这方面想了:首先分析问题的解的结构,分解结构并找出不同规模的结构之间的关系,最后用数据结构,通常是数组实现这个结构。

1. 分析问题解的结构

假设n个老鼠用数字1,2,3,...,n表示,W[i]表示老鼠i的体重,S[i]表示老鼠i的速度,

并假设是最长的一个解序列,即,,

那么问题的解可以由下面的公示表示:

2. 分解问题的解的结构并找出联系

由于满足限制:,则公式中的max范围可以接着转化为:

和分别代表体重最轻的和最重的老鼠,这样一转化之后就可以进一步分解这个结构并看出一些关于动态规划的端倪了,上式等价于:

或者:

这是选取了两种不同的角度去分解解的结构

外层括号内的含义是:拿以W为角度来说,当选取重量在和之间的某一节点,此时和都是确定的,所以对应的范围就不用标出来了,这时满足W,S条件的最大数目

整个公式的含义是:所有可能的值中的最大值

 

记括号内为:

即,问题的解为:

可以分析的特点:

当时,满足W,S条件的节点只有am一个节点,故此时,

当时且的取值随递增时,,由于求解沿着W增大的方向进行,所以只要在已经求解的中选择最大的满足条件的即可,+1表示将作为这个序列的最后一个节点。

 

由于在求解中,需要沿着W增大的方向进行,所以首先需要对输入序列进行排序,使其按照W递增的方向排列。

这时对于的求解只要在中选取符合S条件的最大值即可。

 

三、算法实现

由于要求输出符合条件的节点序号序列,并且在排序后,原来的输入序列序号被打乱,所以需要记录原来的输入序号,这体现在算法的用于保存输入的结构体中。

#include <iostream>    //for cin, cout, endl
#include <algorithm>    //for sort

using std::cin;
using std::cout;
using std::endl;
using std::sort;

typedef struct Data
{
    int w;    //w for weighe
    int s;    //s for speed
    int num;    //original number of data
}data;    //input struct for hold weight and speed of mice

typedef struct Answer
{
    int n;    //n for number, the number of mice
    int prior;    //prior mouse index
}ans;

const int MAXSIZE = 1000;
data d[MAXSIZE];    //hold input
ans a[MAXSIZE];    //store the result for problem

bool sort_data(data d1, data d2)
{
    if(d1.w <= d2.w)
        return true;
    else
        return false;
}
/*
 * name: calculate
 * description: calculate the result
 * return value: int indicates the index of answer array for result
 * argument: n represents the number of input datas
 */
int calculate(int n)
{
    int ret, tmp;    //ret for return, represent return value, tmp for temp, used for swap data

    sort(d, d+n, sort_data);    //sort input data by weight, making weight in an increasing order

    ret = 0;    //ret represent the index of result
    for(int i=0; i<n; i++){    //calculate a[0]~a[n-1]
        a[i].n = 0;    //ans[i] hold the 0, means it has no node to construct result sequence
        a[i].prior = -1;    //-1 represent itself is the last node

        for(int j=0; j<i; j++){    //find the max n valye of a[0]~ans[i-1]
            if(d[i].s < d[j].s){    //if only d[i].s<d[j].s, the a[i].n can based on a[j].n
                tmp = a[j].n;
                if(tmp > a[i].n){    //update a[i].n
                    a[i].n = tmp;
                    a[i].prior = j;
                }
            }
        }
        a[i].n++;    //add itself as the last node of result sequence
        if(a[i].n > a[ret].n)    //update return value for each element of a array
            ret = i;
    }
    return ret;
}
/*
 * name: print_result
 * description: print node sequence of result
 * argument: n represents the index of last node of result
 */
void print_result(int n)
{
    int tmp[MAXSIZE];
    int i=n, j=0;

    cout << a[n].n << endl;
    while(i != -1){
        tmp[j++] = d[i].num;
        i = a[i].prior;
    }
    while(j>0)
        cout << tmp[--j] << endl;
}
int main()
{
    int res, n=0;

    while(cin>>d[n].w>>d[n].s){
        d[n].num = n+1;
        n++;
    }

    res = calculate(n);
    print_result(res);

    return 0;
}

四、小结

可以说有点强行解释了,好像是那样,但是用数学语言却有点难描述,排序后,问题就变得和前一题很相似了,ACM Step3.2.3,记录一下。

10-05 12:53