[HDU 2126] Buy the souvenirs (动态规划)

时间:2024-11-02 16:03:43

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126

题意:给你n个物品,m元钱,问你最多能买个多少物品,并且有多少种解决方案。

一开始想到的是,先解决给m元钱因为我花的钱少就一定能购买够多的物品,因此是个贪心算法。

记买最多的物品数为c。

然后就是设计状态dp[i][j]代表我从前i个物品里花了j元钱,买c个物品有多少种方案。

后来发现状态维数不够,得重新想想。

于是就想到:

设计状态dp[i][j][k]代表我从前i个物品里买了j个,花的钱不超过k元的方案数。

状态转移方程:dp[i][j][k] = dp[i-1][j-1][k-a[i]] + dp[i-1][j][k]

即表示:从前i个物品里买了j个,花的钱不超过k元的方案数为从前i-1个物品里买了j个花钱不超过k元与前i-1个物品里买了j-1个,花钱不超过k-a[i]的方案数之和。

代码:

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <iterator>
#include <vector>
using namespace std;
typedef long long LL; int T,n,m;
const int MAX_N = ;
int a[MAX_N];
int dp[MAX_N][MAX_N][]; int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
memset(dp,,sizeof(dp));
// dp[0][0][0] = 1;
for(int i=;i<=m;i++) dp[][][i] = ;
for(int i=;i<=n;i++){
for(int j=;j<=i;j++){
for(int k=m;k>=;k--){
dp[i][j][k] += dp[i-][j][k];
if( k-a[i]>= ) dp[i][j][k] += dp[i-][j-][k-a[i]];
}
}
}
int maxn = ;
for(int i=;i<=n;i++){
if( dp[n][i][m] ) maxn = i;
}
if( maxn ) printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n",dp[n][maxn][m],maxn);
else puts("Sorry, you can't buy anything.");
}
return ;
}