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

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)
00000
1110220
21251021
313103022
414153223
515204024

手动推算结果:

  • 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)
1111110110201
2122120131311
3133162303331
4144213413501
5155264434611
  • 黄色区域为选择最优结果,分别投资项目1、项目3和项目4以1元、3元、1元可得最大收益61。

3. 设计

动态规划求解投资问题

#include<bits/stdc++.h>
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值