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去取55和66,会比取77的结果更大。
但是如果用了贪心,发现77比22大立刻盲目地选择了77,取了77后确实得到了当前的最大值(局部最优解);
后面检查到55和66时已经不能再选择了,无法得到最终的最大值(全局最优解)。
可能你会问:全局最优解要对全局扫描才知道啊,对N个值循环加循环暴力扫描,不行吧?
确实不行,但是这个所谓全局最优解,并不需要同时对所有值进行扫描;只需要逐步得出每前n个问题的全局最优解就好了。
在你见过这个过程之前,这里没法更详细地展开;为了更形象地解释动态规划,先看看在本题的实际情况:
在这里我随手打了这样一个数据:
11 4 2 3 12 7 10 5 6 8 9 11
如上面所说的,放弃4取2、3,放弃7取5、6,其累加和更大。
下面的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开始逐步模拟:(建议先自己在纸上写一遍,有助理解)
1(4):这里只有4可以选,把棋子移动到4,累加和4; 2(2):前面只有起点可以移动到这里来,累加和2; 3(3):前面有起点和2可以移动到这里来,累加和分别是0与2,取2累加,得5; 4(12):前面有4、2、3可以移动到这里来,累加和分别是4、2、5,取5累加,得17; 5(7):前面有累加和4、2、5,取5累加,得12; !!! 6(10):前面有4、2、3、7,累加和为4、2、5、12,取12累加得22; !!! 7(5):前面有4、2、3,累加和是4、2、5,取5累加得10; 8(6):前面有4、2、3、5,累加和4、2、5、10,取10累加得16; !!! 9(8):前面有4、2、3、7、5、6,累加和4、2、5、12、10、16,取16累加得24。 !!! ……
注意第6步(10)和第9步(8),在第6的状况下,前面的最大累加和在7这里,7的累加和12就是当时的最优解;
而到了第9步,在这里前面有5和6的累加和,那么取6的累加和16才是现在的最优解。
我想现在你应该想出个所以然来了。虽然贪心和动态规划都不知道/不考虑后面的情况,但是对于第n个问题:
贪心只考虑在目前(一个)状况下(从第n-1问题的答案出发),如何得到最大利益;
动态规划考虑在之前(所有)状况下(从前n-1问题的答案中),如何得到最大利益。
(这个贪心的解释不是在解释上文的“贪心”,而是贪心题解中的算法)
我想在这里你应该明白什么叫局部最优解和全局最优解了:
在贪心算法中,它选择的都是目前(n)的最优解,但在第n个问题的选择,在以后不一定是最优的,所以称局部;
动态规划中,它选择的是前面所有答案(1~n)中的最优解,可以保证在每一步它都是取最优解,所以称全局。
也行目前你分不清贪心和动态规划,在你接触过背包问题这种经典动态规划题后,就能明白贪心和动态规划之间的区别。
本题的思路已经非常清晰,只需实现出来即可:
数组dp[1001],dp[ i ]的数值就是前面符合条件(nums[前] < nums[ i ])的dp[前]中的最大值、加上当前这个数值;
最终dp数组中的最大值就是题目的答案。
代码如下:
1 #include2 #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 ) 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 }