HDU1024

题目链接:https://vjudge.net/problem/HDU-1024

解题思路:自己完全没有思路,于是去看了kuangbin大神的题解,看了半天才大概理解了,自己写了一版,然后发现跟题解几乎一毛一样。。。这一题得详详细细地写一篇题解,好好地思考总结一下。

  用num[]数组保存数据,n为数组中的元素总数,m为段数。

  dp[i][j]:在选取第j个数的前提下,将前j个数分成i段所能得到的最大值。

  则对于dp[i][j],有两种决策:1、将第j个数作为第i段的最后一个数(也即让其并在第i段上,并且第i段的最后一个数为第j-1个数;2、将第j个数作为第i段的第一个数(也即让其单独成段)。

  状态转移方程:dp[i][j]=max(dp[i][j-1] + num[j], max(dp[i-1][k] | 0<k<j) + num[j]);

  但是,因为1≤n≤1,000,000而且m的数据范围未知,我们很难开出这么大的dp[][]数组,这个时候需要用到滚动数组的技巧。先上核心代码:

 1           for(i=1;i<=m;i++)
 2           {
 3                   mmmax=-INF;      //对于每一个i,把 mmmax 初始为-INF,一方面,这个 mmmax 可以用来保存对于外层循环的这一个 i 值,把前 j-1 个数分成 i 段所能得到的最大值。
 4                   for(j=i;j<=n;j++)
 5                   {
 6                       dp[j]=max(dp[j-1]+a[j],mmax[j-1]+a[j]);  // dp[j-1] 相当于 dp[i][j-1] ,而 mmax[j-1] 即为 max(dp[i-1][k] | 0<k<j) , mmax[]数组利用记忆化的方式,方便地
 7                                        // 实现了这个功能。
 8 
 9                       mmax[j-1]=mmmax;            //另一方面, mmmax 也起到一个延迟标记的作用,对于内层循环的这一个 j 值 mmmax 保存了把前 j-1 个数分成 i-1 段所能得到的最大值(即直到
10                       mmmax=max(mmmax,dp[j]);     //j对应的数的上一个数的最大值),用 mmmax 更新mmax[j-1],可使对于 j+1 (即内层循环的下一次操作),用到的 mmax[j+1-1]是当i = i-1
11                                                    //(即外层循环的上一次操作)时所对应的 mmax[j] 
12 
13                   }    
14          }      

  至此,这道题就讲的差不多了。

AC代码(作者:kuangbin)

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 #define MAXN 1000000
 6 #define INF 0x7fffffff
 7 int dp[MAXN+10];
 8 int mmax[MAXN+10];
 9 int a[MAXN+10];
10 int main()
11 {
12     int n,m;
13     int i,j,mmmax;
14     while(scanf("%d%d",&m,&n)!=EOF)
15     {
16         for(i=1;i<=n;i++)
17         {
18             scanf("%d",&a[i]);
19             mmax[i]=0;
20             dp[i]=0;
21         }
22         dp[0]=0;
23         mmax[0]=0;    
24         for(i=1;i<=m;i++)
25         {
26                 mmmax=-INF;
27                 for(j=i;j<=n;j++)
28                 {
29                     dp[j]=max(dp[j-1]+a[j],mmax[j-1]+a[j]);
30                     mmax[j-1]=mmmax;
31                     mmmax=max(mmmax,dp[j]);
32                 }    
33         }  
34         printf("%d
",mmmax);  
35           
36     } 
37     return 0;   
38 }    
View Code

附上kuangbin签名:人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想!

“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
原文地址:https://www.cnblogs.com/Blogggggg/p/7200088.html