最小化子序列的最大值的和

本文介绍了如何通过动态规划解决一个寻找整数序列中子序列最大值最小化之和的问题。作者从自己的思路出发,逐步完善代码,最终简化为一个函数实现,展示了动态规划解决问题的过程。
摘要由CSDN通过智能技术生成

问题描述:


程序思路:

我不知道什么是优化子结构及子问题重叠性质,完全凭自己感觉写的思路。

dp[i]表示a[1]a[i]这个整数序列的所有子序列最大值的最小化之和。

因此,有

 

为了方便计算,可设dp[0]=0;可由dp[i+1]的公式计算出dp[1,2,…,8],最后的dp[8]即为结果。

 

程序代码(C++):

#include <iostream>
#include <vector>
const int getNumberMax(const int a, const int b)          //get the max(a,b)
{
    return (a > b)? a : b;
}
 
const int getSumMin(const int a, const int b)            //get the min(a,b)
{
    return (getNumberMax(a, b) == b)? a : b;
}
 
int main()
{
    using std::cout;
    using std::endl;
    using std::cin;
    using std::vector;
 
    vector<int> ivec = { 2, 2, 2, 8, 1, 8, 2, 1 };       //the array a[N]
    int len = static_cast<int> (ivec.size());            //the length of a[]
    const int LIM = 17;                                  //the limit
    vector<int> dp = {0};                                //the array of dp[] and dp[0]=0;
 
    for(int i = 1; i < len + 1; ++i)
    {
        int j = i - 1;
 
        //max to store the max of subarray before a[i](includea[i]).  The sum of subarray<=LIM
        int max = ivec[j]; 
        //sumTemp to store the sum of subarray
        int sumTmp = ivec[j];
        //sumMin to store every value maybe be dp[i]
        int sumMin = ivec[j] + dp[j];
 
        while(j > 0 && (sumTmp + ivec[j]) <= LIM)
        {
            sumTmp+= ivec[j-1];
            max=getNumberMax(max, ivec[j-1]);
            sumMin= getSumMin(sumMin, dp[j-1] + max);
            --j;
        }
        dp.push_back(sumMin);
    }
 
    for(int i : dp)                        //to output dp[0...len]
    {
        cout<< i << ' ';
    }
    cout<< endl;
 
    //to output the result
    cout<< "The result is " << *(dp.end() - 1) << endl;
 
    cin.get();
    return 0;
}


至此,这题已经解决。接下来,分享一下我的做题过程(选读),有兴趣的,可以看一下。


这是实验室的一个师弟问我的题目。当时,一看是动态规划(dynamic plan,DP)的题目。还是有点畏惧,不过所幸题目并不长,我就耐心的读了下来。第一感觉,就是题目不怎么难,我应该能做出来。很快我有了思路,但应该不是动态规划的思路。有点像递归,逐渐缩小规模来做。

接下来,就带着一点懵懂,开干了。编写的过程中,问题不断。情况二出现问题,不能化成相同的子问题。怎么办?好歹也看这么久的书,虽然不是关于算法的,但语言的技巧都还能掌握的。带着一点不服,继续思考。第二天,利用琐碎时间想到解决方法,完成正常递归。

Sub_Max_Min()功能,求vector v[pos]之后len长度的最小化子序列最大值之和的解,也就原问题的解==Sub_Max_Min(ivec,0,ivec.size(),LIM)

Sub()则是考虑左边存在一个子序列,子序列之和为lsum,最大值为lmax,在这个约束条件下,考虑原问题的解。

写完程序吓了一跳,好复杂的感觉。有两个函数,这让我觉得肯定能优化一下。于是,再想了几天,终于化成一个函数。

其实,

Sub_Max_Min(ivec,0,ivec.size(),LIM)=Sub(0,0,ivec,0,ivec.size(),LIM)

于是将二者归一为

int Sum_Max_Min(int lsum, int lmax, const vector<int>& ivec, intpos, int len, const int LIM)

(具体代码见附件1)

接下来,感觉我这种思路无法继续优化下去。于是,往DP上面去想。Dp常用的方法已经全忘了,只记得要找转换公式,于是找了《王道论坛计算机考研机试指南》,看了下dp那章,仔细看了最长递增子序列(LIS)和最长公共子序列(LCS)。之后,对dp的思路形式大体有点掌握,开始继续这个问题。终于当晚来了灵感。第二天,早上立马写出程序。写完,真是日*了---狗了。好简单!思路也很清晰,比我当初的算法简单很多,而且高效。突然,觉得这题好简单,我突然耗了这么多时间,顿时想对自己说了n句傻*。

(具体代码见附件2)


总结与扩展:

  1. 题目总结      (1)最小化->最大值的和   (2)子序列之和不超过 T  (这个条件貌似不好改变)
  2. 题目扩展
    • 最大化-》最大值的和   没啥意思  都是单个子序列
    • 最大化-》最小值的和   没啥意思  都是单个子序列
    • 最小化-》最小值的和   这个可以用贪心来做
  3. 进一步扩展思路:  如果数组里面存在负数如何解决呢;  子序列个数如果存在个数限定呢。考虑加入对异常的处理,比如a[i]>LIM,如何处理。


附件1


#include <vector>

#include <iostream>

 

usingnamespace std;

 

typedef vector<int>::size_type size;

 

long Sub_Max_Min(const vector<int>&, int, size,const int);

long Sub(int lsum,int lmax,const vector<int>& vec,int pos, size len,const int LIM);

 

int main()

{

       int n;

      cin >> n;

      vector<int> ivec;

 

       //input the array of A[]s

       for(int i= 0; i!= n;++i)

       {

             int num;

             cin >> num;

             ivec.push_back(num);

       }

       //input the limitation of B

       int lim;

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值