动态规划算法典型应用之投资问题
-
问题内容:设有 m 元钱,n项投资,函数 f i ( x ) f_i(x) fi(x)表示将 x 元投入第 i 项项目所产生的效益,i= 1,2,…,n,问:如何分配这 m 元钱,使得投资的总收益最高?
-
动态规划算法我们需要将问题划分为子问题,然后从规模小的问题开始计算,计算到某个问题的时候将该问题的计算过程利用到之前以及计算出来的子问题结果来提高效率。这道题的我们可以根据两个参数来划分子问题规模,分别时前k个项目,以及分配x万元前,利用优化函数 F k ( x ) F_k(x) Fk(x)来表示x万元钱投给前k个项目于的最大收益。
-
所以规模最小的问题就是 F 1 ( x ) F_1(x) F1(x)也就是把x万元钱只分配给第一个项目。很显然这时候取得的最大收益就是效益函数 f i ( x ) f_i(x) fi(x)。也就是 F 1 ( 1 ) = f 1 ( 1 ) F_1(1)=f_1(1) F1(1)=f1(1) $ F_1(2) = f_2(2)$ 依次类推
-
之后规模再大一点就是把x万元钱分配给前两个项目,比如 F 2 ( 1 ) F_2(1) F2(1)的意思就是把1万元前分配给前两个项目,那也就有两种可能,第二个项目分配0万元,前1个项目分配1万元,以及 第二个项目分配1万元,前1个项目分配0万元。 我们就拿第一种可能性做例子。第二个项目分配0万元,我们可以根据效益函数 f 2 ( 0 ) f_2(0) f2(0)来直接得到,当然分配0元当然收益0啦2333,然后前1个项目分配1万元获得的收益多少呢?这时候就可以直接用前一个规模的子问题也就是 F 1 ( 1 ) F_1(1) F1(1)来计算啦!最后只要比较一下两种可能性谁大谁小,选择大的就得到了这个规模问题的答案。
-
我们总结一下后就可以得到递推方程。
-
F k ( x ) = m a x 0 ⩽ x k ⩽ x { f k ( x k ) + F k − 1 ( x − x k ) } F_k(x) = \underset {0\leqslant x_k \leqslant x} {max} \{f_k(x_k) + F_{k-1}(x-x_k)\} Fk(x)=0⩽xk⩽xmax{fk(xk)+Fk−1(x−xk)}
-
最后我根据书本的数据,写了一个程序,正确得出了把5万元分配给4个项目的最大收益,可以说小有成就233
-
//投资问题,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; }
-
运行结果
-
好好学习,天天向上!