动态规划求解投资最优问题

1. 问题

  • 一般性描述:
    • m m m 元钱, n n n 项投资项目,函数 f i f_{i} fi 表示将 x x x 元投入第i项项目所产生的效益, i = 1 , 2 , ⋅ ⋅ ⋅ , n i=1,2,···,n i=1,2n
      问:如何分配这 m m m 元钱,使得投资总效益最高?
  • 组合优化问题:
    • 假设分配给第i个项目的钱数是 x i x_{i} xi
    • 目标函数: m a x ( f 1 ( x 1 ) + f 2 ( x 2 ) + ⋅ ⋅ ⋅ + f n ( x n ) ) max({f_1(x_1)+ f_2(x_2)+···+ fn(x_n)}) max(f1(x1)+f2(x2)++fn(xn))
    • 约束条件: x 1 + x 2 + x 3 + ⋅ ⋅ ⋅ + x n = m , x i ∈ n x_1+x_2+x_3+···+x_n=m, xi∈n x1+x2+x3++xn=m,xin

2. 解析

给定投资效益表 ( m = 5 , n = 4 ) (m = 5, n = 4) m=5,n=4

投资 x x x 效益 f 1 ( x ) f_{1}(x) f1(x) f 2 ( x ) f_{2}(x) f2(x) f 3 ( x ) f_{3}(x) f3(x) f 4 ( x ) f_{4}(x) f4(x)
0 0 0 0 0
1 11 0 2 20
2 12 5 10 21
3 13 10 30 22
4 14 15 32 23
5 15 20 40 24

手动推算结果:

  • F k ( x ) F_k(x) Fk(x) 表示 x x x 元投资给前 k k k 个项目的最大收益, k ∈ [ 1 , 2 , . . . , n ] k∈[1,2,...,n] k[1,2,...,n]
  • x k ( y ) x_k(y) xk(y) 表示 y y y 元投资给第 k k k 个项目, k ∈ [ 1 , 2 , . . . , n ] k∈[1,2,...,n] k[1,2,...,n]
投资 X X X F 1 ( x ) F_1(x) F1(x) x 1 ( x ) x_1(x) x1(x) F 2 ( x ) F_2(x) F2(x) x 2 ( x ) x_2(x) x2(x) F 3 ( x ) F_3(x) F3(x) x 3 ( x ) x_3(x) x3(x) F 4 ( x ) F_4(x) F4(x) x 4 ( x ) x_4(x) x4(x)
1 11 1 11 0 11 0 20 1
2 12 2 12 0 13 1 31 1
3 13 3 16 2 30 3 33 1
4 14 4 21 3 41 3 50 1
5 15 5 26 4 43 4 61 1
  • 黄色区域为选择最优结果,分别投资项目1、项目3和项目4以1元、3元、1元可得最大收益61。

3. 设计

动态规划求解投资问题

#include
using namespace std;
const int N = 1e3+10;

int n,m,x;
int f[N][N],F[N][N];

void run() {
	cin>>n>>m;
	for (int j=0;j<=m;j++) {
		for (int i=1;i<=n;i++) {
			cin>>f[i][j];
		}
	}
    //枚举投资
	for (int i=1;i<=n;i++) {
        //枚举前i个共分配j元
		for (int j=0;j<=m;j++) {
            //枚举第i个投资投资k元
			for (int k=0;k<=j;k++) {
				F[i][j] = max(F[i][j],F[i-1][j-k] + f[i][k]);
			}
		}
	}
	printf("mx = %d\n",F[n][m]);
}

int main() {
	run();
	return 0;
}

/*
4 5
0 0 0 0 
11 0 2 20
12 5 10 21
13 10 30 22
14 15 32 23
15 20 40 24

*/

4. 分析

  • F k ( x ) = m a x ( f k ( x k ) + F k − 1 ( x − x k ) ) F_k(x) = max(f_k(x_k)+F_{k-1}(x-x_k)) Fk(x)=max(fk(xk)+Fk1(xxk))
  • x i ∈ [ 0 , . . . , x ] xi∈[0,...,x] xi[0,...,x] 共x+1项, f k ( x k ) + F k − 1 ( x − x k ) f_k(x_k)+F_{k-1}(x-x_k) fk(xk)+Fk1(xxk) 有x+1项,因此有x+1次加,x次比较大小
  • 加法 ∑ k = 2 n ∑ x = 1 m ( x + 1 ) = ( n − 1 ) ∗ m ∗ ( m + 3 ) 2 \sum_{k=2}^{n}\sum_{x=1}^{m}(x+1)=\frac{(n-1)*m*(m+3)}{2} k=2nx=1m(x+1)=2(n1)m(m+3)
  • 比较 ∑ k = 2 n ∑ x = 1 m x = ( n − 1 ) ∗ m ∗ ( m + 1 ) 2 \sum_{k=2}^{n}\sum_{x=1}^{m}x=\frac{(n-1)*m*(m+1)}{2} k=2nx=1mx=2(n1)m(m+1)
  • T ( n , m ) = O ( n ∗ m 2 ) T(n,m) = O(n*m^2) T(n,m)=O(nm2)

5. 源码

https://github.com/a894985555/Algorithm/tree/main/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E6%8A%95%E8%B5%84%E9%97%AE%E9%A2%98

你可能感兴趣的:(算法,算法)