动态规划之投资问题

投资问题

题目描述

  • 设有 m 元钱,n项投资,函数f i ( x )表示将 x 元投入第 i 项项目所产生的效益,i= 1,2,…,n,问:如何分配这 m 元钱,使得投资的总收益最高?

  • 动态规划问题需要将问题划分为子问题,然后求出子问题的最优解,然后利用子问题的解逐级来求出最终问题的解

  • 求解思路:对于这道题我们需要设置两个参数 (1)将项目划分为n各阶段,比如先对第一个项目考虑,然后是两个项目…(2)每个项目下还存在另一个可变参数:X->即投资的钱数

  • 注意!!!:作为约束条件的参数不能讨论子问题,也就是投资的钱数不能作为第一个参数来讨论子问题,因为投资的钱数是投资项目的约束条件

  • (2)首先介绍三个函数:

    1)效益函数f_k(x):

xf_1(x)f_2(x)f_3(x)f_4(x)xf_1(x)f_2(x)f_3(x)f_4(x)
00000313103022
1110220414153223
21251021515204024

2)F_k(x)函数:表示x万元投给前k个项目的最大收益

3)x_*k(x)*函数:表示F_k(x)函数取得最大值时要分配给第K个项目对应的钱数,用于解的回溯

  • 最简单的子问题当然是只投给第一个项目了,此时投资的金额数x=1,2,3,4,5,根据效益函数表格可以很轻松的得到如下数据

    F_1(1) =f_1(1)=11,F_1(2) =f_1(2)=12,F_1(3) =f_1(3)=13,F_1(4) =f_1(4)=14,F_1(5) =f_1(5)=15,

  • 再讲解一下第二步,F_2(x),x的取值为1,2,3,4,5 比如F_2(1)->将一万元分给前两个项目,那么就有两种情况

    (1)第一个项目一万元,第二个项目0元

    (2)第一个项目0元,第二个项目一万元

    *所以F_2(1)=max{ f_ 2(0) + F_1(1) ,f_2(1)+F_1(0) },从(1)(2)中选择出最大的值就代表了F_2(1)的最大值 *

  • 同理可以求出F_*2(2),F_*2(3),*F_*2(3),*F_*2(4),*F_*2(5),这里就不给大家一一展示了 ,在程序中只需要用三个循环就可以实现

  • 备忘录:用来存放我们求出的最大值,用来求出问题的解,用一个二维数组就可以实现

xF_1(x) x_1(x))F_2(x) x_2(x))F_3(x) x_3(x))F_4(x) x_4(x))
111 111 011 020 1
212 212 03 131 1
313 316 230 333 1
414 421 341 350 1
515 526 443 461 1
  • 解的追溯:从表中可知最大的收益是61万元,那么怎么追溯解呢?首先查到x_4(5)的值为1,说明收益最大时第四个项目分到的资金是1万元,那么剩下的4万元分给了前三个项目,所以我们查找到了x_3(4)=3,说明第三个项目分到了3万元,那么前两个小组分到的是1万元,所以x_2(1)=0,说明这一万元全部分给了第一项,第二个项目分到0元,分析到这里这个问题的最优解便为:

    分配方案:x_1=1,x_2=0,x_3=3,x_4=1

    最大收益:F_4(5)=61

  • c++语言实现代码

    //投资问题,m元钱,n项投资,f\[i]\[x]表示将x元投入第i项项目所产生的收益,问如何分配这m元钱使得投资的收益最高?
     //输入:m n f\[n]\[m](根据课本的数据手动给定)
     //输出:最高收益以及如何分配的方法
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int main()
    {
    int m = 5;
    int n = 4;
    int f[5][6] = {0};
    f[1][1] = 11, f[1][2] = 12, f[1][3] = 13, f[1][4] = 14, f[1][5] = 15;
    f[2][1] = 0, f[2][2] = 5, f[2][3] = 10, f[2][4] = 15, f[2][5] = 20;
    f[3][1] = 2, f[3][2] = 10, f[3][3] = 30, f[3][4] = 32, f[3][5] = 40;
    f[4][1] = 20, f[4][2] = 21, f[4][3] = 22, f[4][4] = 23, f[4][5] = 24;
    int F[5][6] = {0}; //F[k][x] 表示 将x万元钱分配到前k个项目取得的最大收益
    int x[5][6] = {0}; //用来储存当F[k][x]取得最大值时, 第k个项目被投资了多少万元钱
    for (int i = 1; i <= 5; i)
    {
    F[1][i] = f[1][i]; //当把i万元前全部分配给第一个项目的时候,取得最大的收益就是对应的收益函数f
    x[1][i] = i;       //因为只有一个项目,全部投!
    }
    for (int i = 2; i <= 4; i) //枚举分配前两个项目、前三个,前四个
    {
    for (int j = 1; j <= 5; j) //枚举投资1万元,2万云……
    {
    int _max = 0;
    for (int k = 0; k <= j; k)
    {
    if (f[i][k] + F[i - 1][j - k] > _max)
    {
    _max = f[i][k] + F[i - 1][j - k]; //更新当前情况的最大收益
    x[i][j] = k;                      //记录下当用j万元钱给前i个项目投资时,第i个项目被投资的钱数k
    }
    }
    F[i][j] = _max;
    }
    }
    cout << "最大收益额为" << F[4][5] << endl;
    int money = 5;
    for (int i = 4; i >= 1; i--) //解的追溯
    {
    cout << "第" << i << "个项目投资" << x[i][money] << "元" << endl;
    money -= x[i][money];
    }
    return 0;
    }
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值