Problem
acm.hdu.edu.cn/showproblem.php?pid=2126
题意
n 种物品,m 元钱,每种只能买一个,要求在能买得到的最多物品种类的方案数
分析
在用 dp 求最多种类数时,顺便记录方案数。求最多种类数就是 0/1 背包。
当买下新物品可以取得更多种类数时,要同时更新方案数;如果钱数相同,买下新物品和不买有相同种类数,说明找到买这么多种物品的新方案,将方案数加上。
注意在初始化方案数时,只少有一种方案:什么都不买。
Source code
#include <stdio.h>
#include <string.h>
#define M 500
#define N 30
int v[N];
// dp[0][i]:钱数为 i 时的最大种类数
// dp[1][i]:dp[0][i] 时的方案数
int dp[2][M+1];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int m, n, i, j;
scanf("%d%d", &n, &m);
for(i=0; i<n; ++i)
scanf("%d", v+i);
memset(dp, 0, sizeof dp);
// 初始方案:什么都不买
for(j=0; j<m; ++j)
dp[1][j] = 1;
for(i=0; i<n; ++i)
for(j=m; j>=v[i]; --j)
if(dp[0][j] < dp[0][j-v[i]] + 1)
{
dp[0][j] = dp[0][j-v[i]] + 1;
dp[1][j] = dp[1][j-v[i]];
}
else if(dp[0][j] == dp[0][j-v[i]] + 1)
dp[1][j] += dp[1][j-v[i]];
if(dp[1][m])
printf("You have %d selection(s) "
"to buy with %d kind(s) of souvenirs.\n",
dp[1][m], dp[0][m]);
else
puts("Sorry, you can't buy anything.");
}
return 0;
}