[ 题解 ] [ 最长上升子序列(和) / DP动态规划 ] HDU – 1087 Super Jumping! Jumping! Jumping!

VJudge题目:https://cn.vjudge.net/contest/279505#problem/I

HDU – 1087 Super Jumping! Jumping! Jumping!http://acm.hdu.edu.cn/showproblem.php?pid=1087


题意:在起点与终点之间,给出N个数值。你的棋子只能从一个数值向后移动到更大的数值上,然后累加这个数值。

起点和终点没有数值,你可以无视。要求你的棋子从起点移动到终点,在路上累加的值最大。


输入:N,同一行给出N个数值。保证本题所有数据都是32位整数(一般int都是4字节);

示例:

Input

3 1 3 2
4 1 2 3 4
4 3 3 2 1
0

Output:

4
10
3

 

https://www.cnblogs.com/Kaidora/p/10514202.html

这是我写的贪心题解,贪心很容易理解,并且有助于理解动态规划。


注意这两题虽然类似但不能类比。总是取最大值 不等于 贪心。


这道题不能用贪心做。纯贪心容易丢失全局最优解。比如:

4 22 77 55 66 

很明显,取22后,放弃77去取5566,会比取77的结果更大。

但是如果用了贪心,发现7722大立刻盲目地选择了77,取了77后确实得到了当前的最大值(局部最优解);

后面检查到5566时已经不能再选择了,无法得到最终的最大值(全局最优解)。


可能你会问:全局最优解要对全局扫描才知道啊,对N个值循环加循环暴力扫描,不行吧?


确实不行,但是这个所谓全局最优解,并不需要同时对所有值进行扫描;只需要逐步得出每前n个问题的全局最优解就好了。


在你见过这个过程之前,这里没法更详细地展开;为了更形象地解释动态规划,先看看在本题的实际情况:

在这里我随手打了这样一个数据:

11 4 2 3 12 7 10 5 6 8 9 11

如上面所说的,放弃423,放弃756,其累加和更大。

下面的11行,给出了从第1考虑到第11的最优解(最大累加和):

 1 4,
 2 4,2,
 3 4,2,5,
 4 4,2,5,17,
 5 4,2,5,17,12,
 6 4,2,5,17,12,22,
 7 4,2,5,17,12,22,10,
 8 4,2,5,17,12,22,10,16,
 9 4,2,5,17,12,22,10,16,24,
10 4,2,5,17,12,22,10,16,24,33,
11 4,2,5,17,12,22,10,16,24,33,44,
12 44

 

我们从1开始逐步模拟:(建议先自己在纸上写一遍,有助理解)

14):这里只有4可以选,把棋子移动到4,累加和4;
22):前面只有起点可以移动到这里来,累加和2;
33):前面有起点和2可以移动到这里来,累加和分别是0与2,取2累加,得5;
412):前面有4、2、3可以移动到这里来,累加和分别是4、25,取5累加,得17;
57):前面有累加和4、25,取5累加,得12;
!!!
610):前面有4、237,累加和为4、2512,取12累加得22;
!!!
75):前面有4、23,累加和是4、25,取5累加得10;
86):前面有4、235,累加和4、2510,取10累加得16;
!!!
98):前面有4、23756,累加和4、25121016,取16累加得24。
!!!
……

注意第6步(10)和第9步(8),在第6的状况下,前面的最大累加和在7这里,7的累加和12就是当时的最优解;

而到了第9步,在这里前面有56的累加和,那么取6的累加和16才是现在的最优解。


我想现在你应该想出个所以然来了。虽然贪心和动态规划都不知道/不考虑后面的情况,但是对于第n个问题:

贪心只考虑在目前(一个)状况下(从第n-1问题的答案出发),如何得到最大利益;

动态规划考虑在之前(所有)状况下(从前n-1问题的答案中),如何得到最大利益。

(这个贪心的解释不是在解释上文的“贪心”,而是贪心题解中的算法)


我想在这里你应该明白什么叫局部最优解和全局最优解了:

在贪心算法中,它选择的都是目前(n)的最优解,但在第n个问题的选择,在以后不一定是最优的,所以称局部;

动态规划中,它选择的是前面所有答案(1n)中的最优解,可以保证在每一步它都是取最优解,所以称全局。


也行目前你分不清贪心和动态规划,在你接触过背包问题这种经典动态规划题后,就能明白贪心和动态规划之间的区别。


本题的思路已经非常清晰,只需实现出来即可:

数组dp[1001]dp[ i ]的数值就是前面符合条件(nums[] < nums[ i ])的dp[]中的最大值、加上当前这个数值;

最终dp数组中的最大值就是题目的答案。


代码如下:

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 int N;
 5 int nums[1001]={0};
 6 int dp[1001]={0};
 7 
 8 int max(int a,int b)
 9 {
10     if(a>b)return a;
11     else return b;
12 }
13 
14 int main()
15 {
16 Start:;
17     scanf("%d",&N);
18     if(N==0)return 0;
19     memset(dp,0,sizeof(dp));
20     for(int i=1;i<=N;i++)
21         scanf("%d",nums+i);
22     
23     int answer=0;
24     for(int n=1;n<=N;n++)
25     {
26         for(int m=0;m<n;m++)
27         {
28             if(nums[n]>nums[m])
29                 dp[n]=max( dp[n] , dp[m] );
30         }
31         dp[n] = dp[n]+nums[n];
32         answer=max(answer,dp[n]);
33         for(int m=1;m<=n;m++)
34             printf("%d,",dp[m]);
35             puts("");
36     }
37     
38     printf("%d\n",answer);
39     
40     goto Start;
41 }

 

posted @ 2019-03-12 18:43  Kaidora  阅读(270)  评论(0编辑  收藏  举报