问题:
设$m$元钱,$n$项投资,函数$f[i][x]$表示将$x$元投入第i项项目所产生的效益,$i=1,2,…,n$.问:如何分配这$m$元钱,使得投资的总效益最高?
解析:
背包问题。
设$dp[i][j]$表示在前$i$个项目投入$j$元所产生的最大效益。
转移方程为:
$dp[i][j] = max( dp[i][j] , dp[i - 1][ j - k] + f[i][k] )$
对于每个项目的投资,可以记录$x[i][j]$表示对于前$i$个项目总共投资$j$元时,对项目$i$的投资。
则对每个项目的投资可以由最后一个倒推回来。
$ans[i] = x[i][m] , m -= ans[i] $
设计(核心代码):
1 for (int i = 1; i <= n; ++i) 2 { 3 for (int j = 0; j <= m; ++j) 4 { 5 for (int k = 0; k <= j; ++k) 6 { 7 if (dp[i][j] < dp[i - 1][j - k] + f[i][k]) 8 { 9 dp[i][j] = dp[i - 1][j - k] + f[i][k]; 10 x[i][j] = k; 11 } 12 } 13 } 14 } 15 ans[n] = x[n][m]; 16 int tmp_m = m - ans[n]; 17 for (int i = n - 1; i >= 1; --i) 18 { 19 ans[i] = x[i][tmp_m]; 20 tmp_m -= ans[i]; 21 }
分析:
复杂度:$O(nm^2)$
源码:
https://github.com/Big-Kelly/Algorithm
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int inf = 2e9 + 7; 5 const ll Inf = 1e18 + 7; 6 const int maxn = 3e3 + 5; 7 const int mod = 1e9 + 7; 8 9 int dp[maxn][maxn]; //dp[i][j]表示前i件投j元的最大收益 10 int f[maxn][maxn]; //f[i][j]表示第i件投资j元的最大收益 11 int x[maxn][maxn]; //x[i][j]表示前i件投入j元时第i件的投资 12 int ans[maxn]; //表示收益最大时每个的投资 13 14 int main() 15 { 16 int n, m; 17 scanf("%d %d", &n, &m); 18 for (int i = 1; i <= n; ++i) 19 { 20 for (int j = 1; j <= m; ++j) 21 { 22 scanf("%d", &f[i][j]); 23 } 24 } 25 for (int i = 1; i <= n; ++i) 26 { 27 for (int j = 0; j <= m; ++j) 28 { 29 for (int k = 0; k <= j; ++k) 30 { 31 if (dp[i][j] < dp[i - 1][j - k] + f[i][k]) 32 { 33 dp[i][j] = dp[i - 1][j - k] + f[i][k]; 34 x[i][j] = k; 35 } 36 } 37 } 38 } 39 ans[n] = x[n][m]; 40 int tmp_m = m - ans[n]; 41 for (int i = n - 1; i >= 1; --i) 42 { 43 ans[i] = x[i][tmp_m]; 44 tmp_m -= ans[i]; 45 } 46 printf("投资的最大收益是%d元 ", dp[n][m]); 47 for (int i = 1; i <= n; ++i) 48 { 49 printf("对第%d个项目的投资为%d元 ", i, ans[i]); 50 } 51 }