动态规划是一种算法设计技术。
特点 1:由交叠的子问题构成;特点2:满足最优法;
投资问题:
有n个项目,有m元可以去投资,列出每个项目的投资与收益情况,问该如何分配这m元?
投入(m) | 项目1(f1/x1) | 项目2(f2/x2) | 项目3(f3/x3) | 项目4(f4/x4) |
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 |
这个问题满足的约束条件为:x1+x2+x3+x4=m
目标函数:max{f1(x1)+f2(x2)+f3(x3)+f4(x4)}
一个推论:一个最优策略的任何子序列一定相对于该子序列开始与结束的最优决策序列。
伪代码:
memset(Fx,0,sizeof(Fx)); //初始化都为0 for (int k=1;k<=n;k++) //前k个项目 for(int x=1;x<=m;x++) //投入x元 for(int z=0;z<=x;z++) //投入项目k为z元 Fx[k][x]=max(Fx[k][x],Fx[k-1][x-z]+f[k][z]);
解析(第一次纯手工dp后,用电子稿写出来......):
n=1 F[1][0]=0 F[1][1]=11 MAX(F[1][1])=11 F[1][0]=0 F[1][1]=11 F[1][2]=12 MAX(F[1][2])=12 F[1][0]=0 F[1][1]=11 F[1][2]=12 F[1][3]=13 MAX(F[1][3])=13 F[1][0]=0 F[1][1]=11 F[1][2]=12 F[1][3]=13 F[1][4]=14 MAX(F[1][4])=14 F[1][0]=0 F[1][1]=11 F[1][2]=12 F[1][3]=13 F[1][4]=14 F[1][5]=15 MAX(F[1][5])=15 n=2 F[2][0]=11 F[2][1]=0 MAX(F[2][1])=11 F[2][0]=12 F[2][1]=11 F[2][2]=5 MAX(F[2][2])=12 F[2][0]=13 F[2][1]=12 F[2][2]=16 F[2][3]=10 MAX(F[2][3])=16 F[2][0]=14 F[2][1]=13 F[2][2]=17 F[2][3]=21 F[2][4]=15 MAX(F[2][4])=21 F[2][0]=15 F[2][1]=14 F[2][2]=18 F[2][3]=22 F[2][4]=26 F[2][5]=20 MAX(F[2][5])=26 n=3 F[3][0]=11 F[3][1]=2 MAX(F[3][1])=11 F[3][0]=12 F[3][1]=13 F[3][2]=10 MAX(F[3][2])=13 F[3][0]=16 F[3][1]=14 F[3][2]=21 F[3][3]=30 MAX(F[3][3])=30 F[3][0]=21 F[3][1]=18 F[3][2]=22 F[3][3]=41 F[3][4]=32 MAX(F[3][4])=41 F[3][0]=26 F[3][1]=23 F[3][2]=26 F[3][3]=42 F[3][4]=43 F[3][5]=40 MAX(F[3][5])=43 n=4 F[4][0]=11 F[4][1]=20 MAX(F[4][1])=20 F[4][0]=13 F[4][1]=31 F[4][2]=34 MAX(F[4][2])=34 F[4][0]=30 F[4][1]=33 F[4][2]=32 F[4][3]=22 MAX(F[4][3])=33 F[4][0]=41 F[4][1]=50 F[4][2]=35 F[4][3]=34 F[4][4]=23 MAX(F[4][4])=50 F[4][0]=43 F[4][1]=61 F[4][2]=51 F[4][3]=35 F[4][4]=34 F[4][5]=24 MAX(F[4][5])=61 最后输出的MAX(F[4][5])=61即为最大收益
源代码
// // main.cpp // 作业7 // // Created by yizhihenpidehou on 2020/4/7. // Copyright © 2020 yizhihenpidehou. All rights reserved. // #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int maxen=200; int Fk[maxen][maxen]={0};//存放第k个项目投资x元可以获得的最大收益 int fk[maxen][maxen]={0};//存放第k个项目x元可以获得的收益 int dp(int n,int m){ for(int k=1;k<=n;k++){//前k个项目 for(int x=1;x<=m;x++){//前K个项目共投资多少钱 for(int z=0;z<=x;z++){//给第K个项目分配多少钱 Fk[k][x]=max(Fk[k][x],fk[k][z]+Fk[k-1][x-z]); //计算钱该怎么分配给第k个项目与前k-1个项目收益最大 } } } return Fk[n][m]; //返回收益最大的情况(因为每次Fk[k][x]都是存最大收益) } int main(int argc, const char * argv[]) { int n=4,m=5;//有4个项目,共有5万元 memset(Fk,0,sizeof(Fk)); memset(fk,0,sizeof(fk)); fk[1][0]=0;fk[1][1]=11;fk[1][2]=12;fk[1][3]=13;fk[1][4]=14;fk[1][5]=15; fk[2][0]=0;fk[2][1]=0;fk[2][2]=5;fk[2][3]=10;fk[2][4]=15;fk[2][5]=20; fk[3][0]=0;fk[3][1]=2;fk[3][2]=10;fk[3][3]=30;fk[3][4]=32;fk[3][5]=40; fk[4][0]=0;fk[4][1]=20;fk[4][2]=21;fk[4][3]=22;fk[4][4]=23;fk[4][5]=24; int maxx=dp(n,m); printf("maxx:%d ",maxx); return 0; }
时间复杂度:O(nm²)