用动态规划思想解决投资问题(基于C/C++)

299 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情

1.问题描述

设有m元钱,n项投资,函数f(x)表示将x元投入第i项项目所产生的效益,i=1,2,3,4,5,6....问:如何分配这m元钱,使得投资的总效益最高? 这里假设钱数的分配都是非负整数,分配给第i个项目的钱数是xi,那么该问题可以描述为:

目标函数 max{f(x1)+f(x2)+...+f(xn)}

约束条件 x1+x2+x3+x4+...xn=m

例如:有5万元钱,4个项目,效益函数如表所示; image.png

2.问题思路

首先得了解什么是动态规划:动态规划(Dynamic Programming)是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题.动态规划在很多领域都有着广泛的应用。 动态规划适用于解决带有最优子结构子问题重叠性质的问题.

  • 最优子结构 : 即是局部最优解能够决定全局最优解(也可以认为是问题可以被分解为子问题来解决),如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质.

  • 子问题重叠 : 即是当使用递归进行自顶向下的求解时,每次产生的子问题不总是新的问题,而是已经被重复计算过的问题.动态规划利用了这种性质,使用一个集合将已经计算过的结果放入其中,当再次遇见重复的问题时,只需要从集合中取出对应的结果.

首先要理清数据在数组中如何存储的,位置在哪里,不然很容易将位置搞混,然后输出错误根据动态规划,先把前面的,投资项目为1个,为2个…为n-1个的算出来,然后一个个叠加,然后算出投资n个项目的最大收益。

3.代码实现

image.png

#include <iostream>
using namespace std;
int main()
{
    int n = 0, m = 0;//输入要投资的项目数量和钱数
    cout << "请输入投资多少个项目:" << endl;
    cin >> n;
    cout << "请输入共投资多少钱:" << endl;
    cin >> m;
    int f[5][6] = {{0,0,0,0,0,0},
                {0,11,12,13,14,15},   //第一个项目投入0,1,2,3,4,5万元,所获得的收益
                {0,0,5,10,15,20},    //第二个项目投入0,1,2,3,4,5万元,所获得的收益
                {0,2,10,30,32,40},  //第三个项目投入0,1,2,3,4,5万元,所获得的收益
                {0,20,21,22,23,24}//第四个项目投入0,1,2,3,4,5万元,所获得的收益
    };
    int F[5][6] = { 0 }; //F[k][x] 表示 将x万元钱分配到前k个项目取得的最大收益
    int x[5][6] = { 0 }; //用来储存当F[k][x]取得最大值时, 第k个项目被投资了多少万元钱
    if (n == 1)
    {
        F[1][m] = f[1][m];
        x[1][m] = m;
    }
    else
    {
        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[n][m] <<"万元"<< endl;
    int money = m;
    for (int i = n; i >= 1; i--) //解的追溯
    {
        cout << "第" << i << "个项目投资" << x[i][money] << "万元" << endl;
        money -= x[i][money];
    }
    return 0;
}

4.总结

  1. 动态规划可帮助在给定约束条件下找到最优解。
  2. 在问题可分解为彼此独立且离散的子问题时,就可用动态规划来解决。
  3. 每个表格都是一个子问题,表格中的值就是要优化的值。