动态规划算法设计——实例1

动态规划算法设计——实例1

最近复习了算法的前两章,第一章主要是基础知识,函数的界以及地推方程求解的几种方法。第二章讲了分治策略。看了很多,但感觉没有吸收到很多东西。想到假期后马上就要交动态规划算法作业了。干脆直接做题。

题目描述

  • m a x   g 1 ( x 1 ) + g 2 ( x 2 ) + g 3 ( x 3 ) max\ g_1(x_1)+g_2(x_2)+g_3(x_3) max g1(x1)+g2(x2)+g3(x3)
  • 限制条件: x 1 2 + x 2 2 + x 3 2 ≤ 10 x_1^2+x_2^2+x_3^2\leq10 x12+x22+x3210
  • 其中 g 1   g 2   g 3 g_1\ g_2 \ g_3 g1 g2 g3是三个不同的收益函数。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oGph15Vo-1620051745606)(动态规划算法设计——实例1.assets/question.jpg)]

题目思路

  • 首先来一波吐槽,这每个x一共才4种取值,直接暴力把每种情况的值算出来,取个最大的不香嘛?2333
  • 这道题要求我们用动态规划的算法来求解。按照我们之前积累的经验,我们需要在求解时需要用到规模更小的子问题,所以用什么参数来划分问题就很重要。我一开始的想法是把x1的值作为一个规模参数,x2的值作为一个参数,然后是x3。后来发现这完全不对,把这三个都列出来不就是暴力求解嘛2333。这时我一点思路都没有,便去看了一眼答案。
  • 答案的优化函数 F k ( y ) F_k(y) Fk(y),k表示选择前k个x,y表示平方和的限制,在这种情况下的最大收益。后来一想,这不是和背包问题的思路一模一样嘛?背包问题的k表示选择前k个物品,然后y表示背包的限重。这里只不过背包限重变成了平方和的限制。
  • 明白了这一点,我们很容易写出递归方程(好吧,也不是很容易
  • F k ( y ) = max ⁡ 0 ≤ x k ≤ ⌊ y ⌋ F k − 1 ( y − x k 2 ) + g k ( x k ) F_k(y)=\max \limits_{0\leq x_k \leq \lfloor \sqrt y \rfloor} F_{k-1}(y-x_k^2)+g_k(x_k) Fk(y)=0xky maxFk1(yxk2)+gk(xk)
  • 当我们选择了前k个x时,我们就需要遍历 x k x_k xk的取值,然后把平方和限制剩余的部分 y − x k 2 y-x_k^2 yxk2在前k-1个x中进行取最大收益,最后加上 x k x_k xk带来的收益 g k ( x k ) g_k(x_k) gk(xk)。就是 F k ( y ) F_k(y) Fk(y)。也就是选择前k个x,在平方和限制为y的情况下的最大收益。

代码实现

#include <iostream>
#include <math.h>
using namespace std;

int main()
{
  int g[4][4] = {0, 0, 0, 0, 2, 4, 7, 11, 5, 10, 16, 20, 8, 12, 17, 22};  //第一个下标来区分不同的投资函数,分别有g1,g2和g3,g0闲置。第二个下标用来表示投资的个数,数目从0~3。
  int F[4][11] = {0};  //优化函数F[k][y],下标k表示选择前k个个x(其实一共也才3个x2333),k表示x_1^2+...+x_k^2 <= y
  int Re[4][11] = {-1}; //备忘录函数,表示在选择前k个x,平方和的限制为y的情况下,选择x_k的个数(可以形象的理解为理解为选择了几个x_k)。
  for (int k = 1; k <= 3; k++)  //遍历k,表示选择前几个x
  {
    for (int y = 0; y <= 10; y++) //遍历y,表示平方和的范围
    {
      int max = 0;
      for (int x = 0; x <= sqrt(y); x++)  //遍历选择的第k个x的取值范围,从0~3
      {
        if ((F[k - 1][y - x * x] + g[k][x]) > max)
        {
          max = F[k - 1][y - x * x] + g[k][x];
          Re[k][y] = x;
        }
      }
      F[k][y] = max;  //得到在选择前k个x,平方和限制为y下的最大收益
    }
  }
  cout << F[3][10] << endl;
  int i = 3;
  int y = 10;
  while (i)
  {
    cout << "x_" << i << "的值:" << Re[i][y] << endl;
    y -= Re[i][y] * Re[i][y];
    i--;
  }
  return 0;
}

//运行结果
➜  algorithm git:(main) ✗ g++ question1.cpp -o question1.exe && ./question1.exe
37
x_3的值:2
x_2的值:2
x_1的值:1

伪代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5klOD8B0-1620051745607)(动态规划算法设计——实例1.assets/answer.jpg)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值