【题意】题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3591 一个人需要购买价格为T元的商品,他身上带有面值为v1 v2 v3 v4 ...vn的货币分别有c1 c2 c3 c4...cn个,
售货员也有这些面值的货币,并且有无限个。问这人购买次商品最小需要和售货员流通的货币的个数是多少个?不超过20000个,超过就输出-1。流通的货币数目=购买人支付的货币数码+售货员找零的货币数目。
【分析】因为购买人支付的货币总价值(也就是支付的钱)可能超过商品价格T,所以把T的最大值10000看成背包容量,而把每个货币每次支付的个数看成价值。另外需要把购买人用多重背包算,因为他的货币数目不是无限的。dp[i][v]表示使用到第i种货币购买价格为v的物品需要支付的最少货币数目。
【AC代码】0ms
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 110
#define INF 0x3f3f3f3f
#define MAXC 20000 //最多给出的货币数目
#define MAXV 10000 //相当于背包容量
int w[MAXN],num[MAXN], dp[MAXC+1], dp2[MAXC+1];
int main ()
{
#ifdef SHY
freopen("e:\\1.txt", "r", stdin);
#endif
int count = 0, n, c;
while(~scanf ("%d %d%*c", &n, &c) && n+c)
{
for(int i = 0; i < n; i++)
scanf ("%d%*c", &w[i]);
for (int i = 0; i < n; i++)
scanf ("%d%*c", &num[i]);
memset(dp,0x3f,sizeof(dp));
dp[0] = 0;
for (int i = 0; i < n; i++)//对购买人多重背包
{
if (num[i]*w[i] >= c)
{
for (int j = w[i]; j <= MAXV; j++)
dp[j] = min(dp[j],dp[j-w[i]]+1);
continue;
}
for (int j = 1; j <= num[i]; num[i] -= j, j <<= 1)
{
int wg = j*w[i];
for (int k = MAXV; k >= wg; k--)
dp[k] = min(dp[k],dp[k-wg]+j);//把每次支付的货币数目看成价值
}
if (num[i] > 0)
{
int wg = num[i]*w[i];
for (int k = MAXV; k >= wg; k--)
dp[k] = min(dp[k],dp[k-wg]+num[i]);
}
}
memset(dp2,0x3f,sizeof(dp2));
dp2[0] = 0;
for (int i = 0; i < n; i++)//对售货员进行完全背包
for (int j = w[i]; j <= MAXV; j++)
dp2[j] = min(dp2[j],dp2[j-w[i]]+1);
int ans = INF;
//找到最小的货币流通数目:min(购买人付的货币数目+售货员减去商品价格c的找零货币数目)
for(int i = c; i <= MAXC; i++)
ans = min(ans,dp[i]+dp2[i-c]);
printf ("Case %d: ", ++count);
if (INF == ans)
puts("-1");
else
printf ("%d\n", ans);
}
return 0;
}