hdu2126 类01背包(三维数组的二维空间优化)

题目描述:

对于给出的n个物品,每个物品有一个价格p[i],你有m元钱,求最多能买的物品个数,以及有多少种不同的方案

题目分析:

类似01背包的题目,一般的01背包问题我们遇到的是求n个物品,有m的容量,每个有w[i]的花费,求出容量范围内的价值的最大值,动态转移方程为dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + value[i]),dp[i][j]存放前i种物品,容量为j时价值的最大值,优化空间之后是dp[j] = max(dp[j], dp[j-w[i]] + value[i]),而用此题去类比01背包的题目的语境,此时把每次纪念品的价格都当做是1,我们需要求的是给定的容量m的最大价值的搭配方法

原来就只需要求最大价值是多少,相当于多了一个维度存放搭配的数目,每一个i对应着一个二维数组,当更新当前第i个二维数组时,是根据第i-1个二维数组里的值更新的,所以此时需要用到三维数组存放,优化空间后可以用二维数组,且第2,3层循环都需要从大到小,避免干扰

套用01背包对动态转移方程进行推导优化之前,dp[i][j][k]表示前i件物品,当有j元钱(不超过j元钱),可以购买k个物品的种数dp[i][j][k] = dp[i-1][j][k] + dp[i-1][j-p[i]][k-1],(前i个物品的有j元,买k个物品的种数为前i-1个物品j元买k个(第i个不买)或者i-1个物品j-p[i]元买k-1件物品的种数(第i个买)),优化空间后为dp[j][k] = dp[j][k] + dp[j-p[i]][k-1]

需要注意的是初始化dp[i][0]都为1,意思是i元钱买0种物品的选择方案有1种就是不买

代码:

 1 #include<iostream>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 using namespace std;
 7 
 8 int p[35];
 9 int dp[505][35];
10 
11 int main(){
12     int t;
13     scanf("%d", &t);
14     while(t--){
15         int n, m;
16         scanf("%d%d", &n, &m);
17         for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
18         sort(p+1, p+n+1);
19         int sum = 0;
20         int ma = 0;
21         for(int i = 1; i <= n; i++){
22             if(sum + p[i] <= m){
23                 sum += p[i];
24                 ma = i;
25             }
26         }
27         memset(dp, 0, sizeof(dp));
28         for(int i = 0; i <= m; i++) dp[i][0] = 1;
29         for(int i = 1; i <= n; i++){
30             for(int j = m; j >= p[i]; j--){
31                 for(int k = ma; k >= 1; k--){
32                     dp[j][k] += dp[j-p[i]][k-1];
33                 }
34             }
35         }
36         if(ma != 0){
37             printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n", dp[m][ma], ma);
38         }else{
39             printf("Sorry, you can't buy anything.\n");
40         }
41     }
42     return 0;
43 }

猜你喜欢

转载自www.cnblogs.com/findview/p/11888388.html
今日推荐