投资问题
1. 问题
设m元钱,n项投资,函数f[i][x]表示将x元投入第i项项目所产生的效益,i=1,2,…,n.问:如何分配这m元钱,使得投资的总效益最高?
2. 解析
递推公式:
设F[k][x]表示x万元投给前k个项目的最大效益,k=1,2,…,n,x=1,2,…,m
递推方程:F[k][x]=max{f[k][j]+F[k-1][x-j]} , 0<=j<=x , k=1,2,…,n 边界条件:F[1][x]=f[1][x] , x=0,1,…,m ; F[k][0]=0 , k=1,2,…,n |
说明:第k步,共分配x万元
① 其中分配给第k个项目为j万元;
② 分配给前k-1的项目为x-j万元。
满足优化原则:
优化原则:一个最优决策序列的任何子序列本身一定是相对于子序列的初始和结束状态的最优决策序列。
已知:这个序列L1时最优决策序列
那么:这个序列任何子序列本身一定是相对于子序列的初始和结束状态的最优决策序列。
3. 设计
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=100+10; 6 const int maxm=1000+10; 7 int f[maxn][maxm]; //f[i][j], 表示j元投资给前i个项目的最大收益 8 int val[maxn][maxm]; //val[i][j],表示投资第i件j元的收益 9 int x[maxn][maxm]; //x[i][j],表示在总共分配j元时, 取得最大效益时分配给第i个项目的钱数 10 int n,m; //n件物品,总投资m元 11 int main(){ 12 scanf("%d %d",&n,&m); 13 for(int i=0;i<=m;++i){ 14 printf("当投资%d元时,请输入每件物品的收益: ",i); 15 for(int j=1;j<=n;++j){ 16 scanf("%d",&val[j][i]); 17 } 18 } 19 for(int i=1;i<=n;++i){ 20 for(int j=0;j<=m;++j){ 21 for(int k=0;k<=j;++k){ 22 if(f[i-1][j-k]+val[i][k]>f[i][j]){ 23 f[i][j]=f[i-1][j-k]+val[i][k]; 24 x[i][j]=k; 25 } 26 27 } 28 } 29 } 30 for(int i=1;i<=m;++i){ 31 for(int j=1;j<=n;++j){ 32 printf(" %d %d ",f[j][i],x[j][i]); 33 } 34 printf(" "); 35 } 36 printf("最大收益为:%d ",f[n][m]); 37 } 38 /* 39 4 5 40 0 0 0 0 41 11 0 2 20 42 12 5 10 21 43 13 10 30 22 44 14 15 32 23 45 15 20 40 24 46 */
4. 分析
k∈[0,j],共j+1项,f[i][k]+F[i-1][j-k]有j+1项,因此有j+1次加法,j+1项比较出最大值。
for i = 1 ~ n
for j = 0 ~ m
for k= 0 ~ j
加法与比较的复杂度均为(n-1)m(m+3)/2.
因此该算法时间复杂度为O(n·m^2)
5. 源码
https://github.com/JayShao-Xie/algorithm-work/blob/master/dp_ex1.cpp