持续创作,加速成长!这是我参与「掘金日新计划 · 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个项目,效益函数如表所示;
2.问题思路
首先得了解什么是动态规划:动态规划(Dynamic Programming)是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题.动态规划在很多领域都有着广泛的应用。
动态规划适用于解决带有最优子结构和子问题重叠性质的问题.
-
最优子结构: 即是局部最优解能够决定全局最优解(也可以认为是问题可以被分解为子问题来解决),如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质. -
子问题重叠: 即是当使用递归进行自顶向下的求解时,每次产生的子问题不总是新的问题,而是已经被重复计算过的问题.动态规划利用了这种性质,使用一个集合将已经计算过的结果放入其中,当再次遇见重复的问题时,只需要从集合中取出对应的结果.
首先要理清数据在数组中如何存储的,位置在哪里,不然很容易将位置搞混,然后输出错误根据动态规划,先把前面的,投资项目为1个,为2个…为n-1个的算出来,然后一个个叠加,然后算出投资n个项目的最大收益。
3.代码实现
#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.总结
- 动态规划可帮助在给定约束条件下找到最优解。
- 在问题可分解为彼此独立且离散的子问题时,就可用动态规划来解决。
- 每个表格都是一个子问题,表格中的值就是要优化的值。