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

时间:2023-03-09 00:04:13
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种就是不买

代码:

 #include<iostream>
#include<string.h>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std; int p[];
int dp[][]; int main(){
int t;
scanf("%d", &t);
while(t--){
int n, m;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) scanf("%d", &p[i]);
sort(p+, p+n+);
int sum = ;
int ma = ;
for(int i = ; i <= n; i++){
if(sum + p[i] <= m){
sum += p[i];
ma = i;
}
}
memset(dp, , sizeof(dp));
for(int i = ; i <= m; i++) dp[i][] = ;
for(int i = ; i <= n; i++){
for(int j = m; j >= p[i]; j--){
for(int k = ma; k >= ; k--){
dp[j][k] += dp[j-p[i]][k-];
}
}
}
if(ma != ){
printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n", dp[m][ma], ma);
}else{
printf("Sorry, you can't buy anything.\n");
}
}
return ;
}