【动态规划】投资问题

本文利用markdown基于https://blog.csdn.net/qq_41926985/article/details/105627049重写,代码部分为本人编辑

代码要求

应用动态规划方法,求解投资问题,实现下面的例子。

#define MAX_N 4 //最大投资项目数目
#define MAX_M 5 //最大投资钱数(万元)
//f[i][j]的意义:第 i(从 1 开始)个项目投资 j 万元的收益
int f[MAX_N+1][MAX_M+1] = {{0,0,0,0,0,0},{0,11,12,13,14,15},{0,0,5,10,15,20},{0,2,10,30,32,40},{0,20,21,22,23,24}
}; 

投资问题

什么是投资问题

m m m元钱, n n n项投资, f i ( x ) f_i(x) fi(x):将x元投入第i个项目的效益。求使得的总效益最大的投资方案。

举个例子:现在有两个项目x是钱数(单位:元),

f i ( x ) f_i(x) fi(x):将x元钱投资到第i个项目产生的效益

注意:使用的是总共的x钱数投资两个项目,而不是分别投资。

alt

将0元投资这两个项目,则最大收益就是0

将1元投资这两个项目,不难看出

f 1 ( 1 ) + f 2 ( 0 ) = 11 f_1(1)+f_2(0)=11 f1(1)+f2(0)=11

,是最大收益

将2元投资这两个项目,不难看出

f 1 ( 2 ) + f 2 ( 0 ) = 12 f_1(2)+f_2(0)=12 f1(2)+f2(0)=12

,是最大收益

将3元投资这两个项目,

m a x ( f 1 ( 0 ) + f 2 ( 3 ) , f 1 ( 1 ) + f 2 ( 2 ) , f 1 ( 2 ) + f 2 ( 1 ) , f 1 ( 3 ) + f 2 ( 0 ) ) = f 1 ( 1 ) + f 2 ( 2 ) = 16 max(f_1(0)+f_2(3),f_1(1)+f_2(2),f_1(2)+f_2(1),f_1(3)+f_2(0)) =f_1(1)+f_2(2)=16 max(f1(0)+f2(3)f1(1)+f2(2)f1(2)+f2(1)f1(3)+f2(0))=f1(1)+f2(2)=16

,是最大收益

同样的用4元或者5元投资这两个项目,所带来的最大收益分别是21和26

我们接下来对问题进行建模:

目标函数:利用所分配的投资产生最大效益

约束条件:是在总资金的条件下进行投资

alt

建模

问题的解是向量 < x 1 , x 2 , ⋅ ⋅ ⋅ , x n > <x_1,x_2,···,x_n> <x1,x2,⋅⋅⋅,xn>

x i x_i xi是投给项目的钱数, i = 1 , 2 , ⋅ ⋅ ⋅ , n . i=1,2,···,n. i=1,2,⋅⋅⋅,n.

目标函数 m a x { f 1 ( x 1 ) + f 2 ( x 2 ) + ⋅ ⋅ ⋅ + f n ( x n ) } max \{f_1(x_1)+f_2(x_2)+···+f_n(x_n)\} max{f1(x1)+f2(x2)+⋅⋅⋅+fn(xn)}

约束条件: x 1 + x 2 + ⋅ ⋅ ⋅ + x n = m , x i ∈ N x_1+x_2+···+x_n=m,x_i\in N x1+x2+⋅⋅⋅+xn=m,xiN

下面我们来考虑用动态规划算法来解投资问题

动态规划算法来解投资问题

子问题的界定:由参数 k k k x x x界定

k k k:考虑对每个项目 1 , 2 , … , k 1,2,…,k 12k的投资

x x x:投资总钱数不超过 x x x

接下来我们再看一下递推方程

F k ( x ) : x F_k(x):x Fk(x):x元钱投给前k个项目的最大效益

我们可以这么想,假如我们要求 F k ( x ) F_k(x) Fk(x),即就是求x元钱投给前 k k k个项目的最大效益。那不妨求 p p p元钱 ( p ≤ x ) (p\leq x) (px)投给前k-1个项目的最大效益 F k − 1 ( p ) F_{k-1}(p) Fk1(p),进而确定 F k ( x ) F_k(x) Fk(x)

我们进而可以列出递推方程:

alt

我们看到啊, F k ( x ) F_k(x) Fk(x)的求解,就是去求用 x − x k x-x_k xxk分配前 k − 1 k-1 k1个项目所产生的最大效益。然而这个最大效益是在备忘录存着来。没错备忘录的作用就是存储最大的效益。
F 1 ( x ) F_1(x) F1(x):就是在投资表中的用x钱投资第一个项目的收益

接下来我们看个例子:
这是一个投资——效益表

ALT

我们要先明确最小子问题是什么,然后才能从这个最小子问题开始算起;然后考虑计算顺序,保证后面的值在前面已经计算好。

这里我们看到第一个项目的最大收益就是投资对应的收益,即
F 1 ( 0 ) = 0 , F 1 ( 1 ) = 11 , F 1 ( 2 ) = 12 , F 1 ( 3 ) = 13 , F 1 ( 4 ) = 14 , F 1 ( 5 ) = 15 。 (1) F_1(0)=0,F_1(1)=11,F_1(2)=12,F_1(3)=13,F_1(4)=14,F_1(5)=15。\tag{1} F1(0)=0F1(1)=11F1(2)=12F1(3)=13F1(4)=14F1(5)=15(1)

我们能看到啊,前1个项目可以定为最小子问题,它的初值可以通过查表得到,不用计算。而后面的项目随着项目的增多,子问题的复杂性就会增强。因此我们根据项目序列的递增关系来计算,从而保证后面的值在前面已经计算好了。

我们通过上面的递推方程可以得知,用 x − x k x-x_k xxk分配前 k − 1 k-1 k1个项目所产生的最大效益越大以及x元钱投给前k个项目的最大效益越大,从而使得原问题的解达到最大。进而满足依赖关系。而对于 x k x_k xk为何值,这个是需要通过计算获取最优解来得到。

好,我们来继续看前两个项目的最大效益:
我们先看 x = 0 x=0 x=0,则最大效益是0

再来看 x k = 1 x_k=1 xk=1 F 2 ( 1 ) = m a x { f 2 ( 1 ) + F 1 ( 1 − 1 ) , f 2 ( 0 ) + F 1 ( 1 − 0 ) } = 11 F_2(1)=max\{f_2(1)+F_1(1-1),f_2(0)+F_1(1-0)\}=11 F2(1)=max{f2(1)+F1(11)f2(0)+F1(10)}=11
再来看 x k = 2 x_k=2 xk=2 F 2 ( 2 ) = m a x { f 2 ( 2 ) + F 1 ( 2 − 2 ) , f 2 ( 1 ) + F 1 ( 2 − 1 ) , f 2 ( 0 ) + F 1 ( 2 − 0 ) } = 12 F_2(2)=max\{f_2(2)+F_1(2-2),f_2(1)+F_1(2-1),f_2(0)+F_1(2-0)\}=12 F2(2)=max{f2(2)+F1(22)f2(1)+F1(21)f2(0)+F1(20)}=12
再来看 x k = 3 x_k=3 xk=3 F 2 ( 3 ) = m a x { f 2 ( 3 ) + F 1 ( 3 − 3 ) , f 2 ( 2 ) + F 1 ( 3 − 2 ) , f 2 ( 1 ) + F 1 ( 3 − 1 ) , f 2 ( 0 ) + F 1 ( 3 − 0 ) } = 16 F_2(3)=max\{f2(3)+F_1(3-3),f_2(2)+F_1(3-2),f_2(1)+F_1(3-1),f_2(0)+F_1(3-0)\}=16 F2(3)=max{f2(3)+F1(33)f2(2)+F1(32)f2(1)+F1(31)f2(0)+F1(30)}=16
同样的 F 2 ( 4 ) = 21 , F 2 ( 5 ) = 26 F_2(4)=21,F_2(5)=26 F2(4)=21F2(5)=26

当然,这里得到的 F 2 ( 1 ) , F 2 ( 2 ) , F 2 ( 3 ) , F 2 ( 4 ) , F 2 ( 5 ) F_2(1),F_2(2),F_2(3),F_2(4),F_2(5) F2(1)F2(2)F2(3)F2(4)F2(5)要记录到备忘录里面。

那么如何去记录解?
我们用 s s s数组来记录解。我们去记录在得到最大效益的时候,最后一个项目给了多少钱。
就如同上面的例子,在前两个项目的最大收益中。
x i ( x ) : x_i(x): xi(x):分配x元钱给前i个项目,在最大收益时,第i个项目得到了多少钱
x 2 ( 1 ) : x_2(1): x2(1):看到啊, F 2 ( 1 ) = f 2 ( 0 ) + F 1 ( 1 − 0 ) = 11 F_2(1)=f_2(0)+F_1(1-0)=11 F2(1)=f2(0)+F1(10)=11。此时,第2个项目得到了0元钱
x 2 ( 2 ) : f 2 ( 0 ) + F 1 ( 2 − 0 ) = 12 x_2(2):f_2(0)+F_1(2-0)=12 x2(2):f2(0)+F1(20)=12。此时,第2个项目得到了0元钱
x 2 ( 3 ) : f 2 ( 2 ) + F 1 ( 3 − 2 ) = 16 x_2(3):f_2(2)+F_1(3-2)=16 x2(3):f2(2)+F1(32)=16。此时,第2个项目得到了2元钱
同样的,我们也能得到 x 2 ( 4 ) = 3 , x 2 ( 5 ) = 4 x_2(4)=3,x_2(5)=4 x2(4)=3x2(5)=4

ok,下面介绍一下如何追踪解
上面的投资问题的结果如图所示:

alt

我们细想,原问题是用5元钱分配所有项目(这里就是4个项目),所得到的最大收益
这个最大收益是不是就是 F 4 ( 5 ) F_4(5) F4(5)
( F 4 ( 5 ) F_4(5) F4(5):用5元钱分配前4个项目得到的最大收益)
,那这个值就可以去衡量原问题的解。因此我们追踪解也要从 x 4 ( 5 ) x_4(5) x4(5)开始,自底向上追踪。

先看到x4(5)=1,说明达到最大收益的时候分配给最后一个项目,即第4个项目是1元钱。
那么第3个项目呢?
第3个项目就是 x 3 ( x ) x_3(x) x3(x),这个x就是5-1=4,就是用总共的5元钱-分配给第4个项目的钱数。
x 3 ( 5 − 1 ) = 3 x_3(5-1)=3 x3(51)=3。因此在得到最大收益时,分配给第3个项目3元钱。
同理 x 2 ( 4 − 3 ) = 0 , x 1 ( 1 − 0 ) = 1 x_2(4-3)=0,x_1(1-0)=1 x2(43)=0x1(10)=1
也许你会问为什么要这么解?
我们看那个递推方程,我们既然知道 F 4 ( x 5 ) = f 4 ( x 4 ) + F 3 ( x − x 4 ) F_4(x_5)=f_4(x_4)+F_3(x-x_4) F4(x5)=f4(x4)+F3(xx4)。然而我们知道了在最大收益时,分配给第4个项目1元钱,这个可以通过代码可以实现。

F 3 ( 4 ) F_3(4) F3(4),这个通过查表即可得到41,此时分配给它的钱就是3。同样的也可以逆推出 F 2 F_2 F2 F 1 F_1 F1中的 x 2 和 x 1 x_2和x_1 x2x1。就是通过前k-1个项目的最大收益+用剩下钱分配给第k个项目的收益。然而前 k − 1 k-1 k1个项目的最大收益是保存在了我们的备忘录中,所以这个值不仅可以查到,而且它只计算了一次。没有重复计算。使得这个唯一确定的值+ f 4 ( x 4 ) f_4(x_4) f4(x4)值就是最大收益。

因此我们抛去 f 4 ( x 4 ) f_4(x_4) f4(x4)的值,也就是前k个项目的最大收益 F 3 ( x − x 4 ) F_3(x-x_4) F3(xx4)

因此我们可以通过查表得到 x 3 ( x − x 4 ) x_3(x-x_4) x3(xx4)。故这样计算是合理的

#include<bits/stdc++.h>
using namespace std;
#define MAX_N 4 //最大投资项目数目
#define MAX_M 5 //最大投资钱数(万元)
//f[i][j]的意义:第 i(从 1 开始)个项目投资 j 万元的收益
int f[MAX_N+1][MAX_M+1] = {{0,0,0,0,0,0},{0,11,12,13,14,15},{0,0,5,10,15,20},{0,2,10,30,32,40},{0,20,21,22,23,24}
}; void printNum(int num[MAX_N+1][MAX_M+1]){for(int i=0;i<=MAX_M;i++){for(int j=0;j<=MAX_N;j++){cout << num[j][i] << " ";}cout << endl;}return;
}int main()
{int s[MAX_N+1][MAX_M+1] = {0};//s数组用于记录最后一个项目分配的钱int F[MAX_N+1][MAX_M+1] = {0};for(int i=0;i<=MAX_M;i++){F[1][i] = f[1][i];s[1][i] = i;}for(int i=2;i<=MAX_N;i++){for(int j=0;j<=MAX_M;j++){int max = F[i-1][j];int cnt = 0;for(int k=0;k<=j;k++){int num = f[i][k]+F[i-1][j-k];if(num>=max){max = num;cnt = k;}}F[i][j] = max;s[i][j] = cnt;}}printNum(f);cout << endl;printNum(s);cout << endl;printNum(F);cout << endl;int res = s[MAX_N][MAX_M];int pro = MAX_N;int m = MAX_M;while(pro>0){cout << "第" << pro << "个项目的钱数为:" << res << endl;;pro-=1;m-=res;res = s[pro][m];}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/6733.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器视觉】yolo-world-opencvsharp-.net4.8 C# 窗体应用程序

这段代码是基于 OpenCvSharp, OpenVinoSharp 和 .NET Framework 4.8 的 Windows Forms 应用程序。其主要目的是加载和编译机器学习模型&#xff0c;对输入数据进行推理&#xff0c;并显示结果。 下面是该程序的主要功能和方法的详细总结&#xff1a; 初始化 OpenVINO 运行时核心…

基于Pytorch深度学习——卷积神经网络(卷积层/池化层/多输入多输出通道/填充和步幅/)

本文章来源于对李沐动手深度学习代码以及原理的理解&#xff0c;并且由于李沐老师的代码能力很强&#xff0c;以及视频中讲解代码的部分较少&#xff0c;所以这里将代码进行尽量逐行详细解释 并且由于pytorch的语法有些小伙伴可能并不熟悉&#xff0c;所以我们会采用逐行解释小…

【DPU系列之】如何通过带外口登录到DPU上的ARM服务器?(Bluefield2举例)

文章目录 1. 背景说明2. 详细操作步骤2.1 目标拓扑结构2.2 连接DPU带外口网线&#xff0c;并获取IP地址2.3 ssh登录到DPU 3. 进一步看看系统的一些信息3.1 CPU信息&#xff1a;8核A723.2 内存信息 16GB3.3 查看ibdev设备 3.4 使用小工具pcie2netdev查看信息3.5 查看PCIe设备信息…

python笔记:gensim进行LDA

理论部分&#xff1a;NLP 笔记&#xff1a;Latent Dirichlet Allocation &#xff08;介绍篇&#xff09;-CSDN博客 参考内容&#xff1a;DengYangyong/LDA_gensim: 用gensim训练LDA模型&#xff0c;进行新闻文本主题分析 (github.com) 1 导入库 import jieba,os,re from ge…

【云原生】Docker 的网络通信

Docker 的网络通信 1.Docker 容器网络通信的基本原理1.1 查看 Docker 容器网络1.2 宿主机与 Docker 容器建立网络通信的过程 2.使用命令查看 Docker 的网络配置信息3.Docker 的 4 种网络通信模式3.1 bridge 模式3.2 host 模式3.3 container 模式3.4 none 模式 4.容器间的通信4.…

Stream流操作

看到Stream流这个概念&#xff0c;我们很容易将其于IO流联系在一起&#xff0c;事实上&#xff0c;两者并没有什么关系&#xff0c;IO流是用于处理数据传输的&#xff0c;而Stream流则是用于操作集合的。 当然&#xff0c;为了方便我们区分&#xff0c;我们依旧在这里复习一下…

长期找 AI 专家,邀请参加线上聊天直播

诚邀 AI 专家参加线上聊天&#xff0c;成为嘉宾。 分享前沿观点、探讨科技和生活 除节假日外&#xff0c;每周举办在线聊天直播 根据话题和自愿形式结合&#xff0c;每期 2~3 位嘉宾 成为嘉宾&#xff0c;见下&#xff1a;

ADS软件(PathWave 先进设计系统软件)分享与安装

ADS软件的简介 ADS软件&#xff08;Advanced Design System&#xff09;主要用于射频&#xff08;RF&#xff09;、微波&#xff08;Microwave&#xff09;和毫米波&#xff08;Millimeter-wave&#xff09;电路的设计、仿真和分析。它提供了一套强大的工具和功能&#xff0c;…

Angular进阶-NVM管理Node.js实现不同版本Angular环境切换

一、NVM介绍 1. NVM简介 Node Version Manager&#xff08;NVM&#xff09;是一个用于管理多个Node.js版本的工具。它允许用户在同一台机器上安装和使用多个Node.js版本&#xff0c;非常适合需要同时进行多个项目的开发者。NVM是开源的&#xff0c;支持MacOS、Windows和Linux…

【解决】docker一键部署报错

项目场景见&#xff1a;【记录】Springboot项目集成docker实现一键部署-CSDN博客 问题&#xff1a; 1.docker images 有tag为none的镜像存在。 2.有同事反馈&#xff0c;第一次启动docker-compose up -d 项目无法正常启动。后续正常。 原因&#xff1a; 1.服务中指定了镜像m…

Jackson-jr 对比 Jackson

关于Jackson-jr 对比 Jackson 的内容&#xff0c;有人在做了一张下面的图。 简单点来说就 Jackson-jr 是Jackson 的轻量级应用&#xff0c;因为我们在很多时候都用不到 Jackson 的很多复杂功能。 对很多应用来说&#xff0c;我们可能只需要使用简单的 JSON 读写即可。 如我们…

【Linux网络】网络文件共享

目录 一、存储类型 二、FTP文件传输协议 2.1 FTP工作原理 2.2 FTP用户类型 2.3 FTP软件使用 2.3.1 服务端软件vsftpd 2.3.2 客户端软件ftp 2.4 FTP的应用 2.4.1 修改端口号 2.4.2 匿名用户的权限 2.4.3 传输速率 三、NFS 3.1 工作原理 3.2 NFS软件介绍 3.3 NFS配…

企业级数据治理学习总结

1. 水在前面 “数据治理”绝对是吹过的牛里面最高大上的题目了&#xff0c;本来想直接以《企业级数据治理》为题来水的&#xff0c;码字前又跑去图书馆借了几本书&#xff0c;翻了几页才发现自己连半桶水都提不起&#xff0c;撑死只能在小屁孩跟前吹吹牛。 好吧&#xff0c;实在…

怎么把jpg图片变成gif?参考这个方法一键制作

Jpg图片如何变成gif图片&#xff1f;Jpg、gif都是最常用的图片格式&#xff0c;想要将这两种格式的图片互相转化的时候要怎么操作呢&#xff1f;想要将jpg图片变成gif方法很简单&#xff0c;只需要使用gif图片制作&#xff08;https://www.gif5.net/&#xff09;工具-GIF5工具网…

华为手机ip地址怎么切换

随着移动互联网的普及&#xff0c;IP地址成为了我们手机上网的重要标识。然而&#xff0c;在某些情况下&#xff0c;我们可能需要切换手机的IP地址&#xff0c;以更好地保护个人隐私、访问特定地区的内容或服务&#xff0c;或者出于其他网络需求。华为手机作为市场上的热门品牌…

用队列实现栈——leetcode刷题

题目的要求是用两个队列实现栈&#xff0c;首先我们要考虑队列的特点&#xff1a;先入先出&#xff0c;栈的特点&#xff1a;后入先出&#xff0c;所以我们的目标就是如何让先入栈的成员后出栈&#xff0c;后入栈的成员先出栈。 因为有两个队列&#xff0c;于是我们可以这样想&…

vue3(实现上下无限来往滚动)

一、问题描述 一般在大屏项目中&#xff0c;很常见的效果&#xff0c;就是容器中的内容缓慢地向下移动&#xff0c;直到底部停止&#xff0c;然后快速滚动回顶部&#xff0c;然后接着缓慢滚动到底部。并且在特定的情况下&#xff0c;还需要进行一些小交互&#xff0c;那就还得让…

Leetcode——面试题02.04.分割链表

面试题 02.04. 分割链表 - 力扣&#xff08;LeetCode&#xff09; 对于该链表OJ&#xff0c;我们两种大的方向&#xff1a; 1.在原链表上修改&#xff1b;2.创建新链表&#xff0c;遍历原链表。 在原链上进行修改&#xff1a;如果该节点的val小于x则继续往后走&#xff0c;如…

Ubuntu服务器创建新用户及解决新用户登录Access denied问题

目录 Ubuntu服务器创建新用户及解决新用户登录Access denied问题创建账号步骤创建用户只创建用户添加用户到sudo组 允许账号远程连接重启ssh服务 删除账号要删除用户而不删除用户文件如果要删除并且删除用户的家目录和邮件 查询指令查看所有用户查询特定用户账户信息查看用户组…

【Micropython Pitaya Lite教程】key按键与EXTI中断

文章目录 前言一、按键的使用1.1 按键的简介1.2 读取按键的高低电平 二、EXIT外部中断2.1 EXIT外部中断简介2.2 外部中断基础知识2.3 设置外部中断2.4 示例代码 总结 前言 Micropython Pitaya Lite开发板提供了丰富的功能和灵活的扩展性&#xff0c;其中包括了按键&#xff08…