背包专题C - The trouble of Xiaoqian hdu3591混合背包:多重背包+完全背包

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包专题C - The trouble of Xiaoqian hdu3591混合背包:多重背包+完全背包相关的知识,希望对你有一定的参考价值。

In the country of ALPC , Xiaoqian is a very famous mathematician. She is immersed in calculate, and she want to use the minimum number of coins in every shopping. (The numbers of the shopping include the coins she gave the store and the store backed to her.) 
And now , Xiaoqian wants to buy T (1 ≤ T ≤ 10,000) cents of supplies. The currency system has N (1 ≤ N ≤ 100) different coins, with values V1, V2, ..., VN (1 ≤ Vi ≤ 120). Xiaoqian is carrying C1 coins of value V1, C2 coins of value V2, ...., and CN coins of value VN (0 ≤ Ci ≤ 10,000). The shopkeeper has an unlimited supply of all the coins, and always makes change in the most efficient manner .But Xiaoqian is a low-pitched girl , she wouldn’t like giving out more than 20000 once. 

InputThere are several test cases in the input. 
Line 1: Two space-separated integers: N and T. 
Line 2: N space-separated integers, respectively V1, V2, ..., VN coins (V1, ...VN) 
Line 3: N space-separated integers, respectively C1, C2, ..., CN 
The end of the input is a double 0. 
OutputOutput one line for each test case like this ”Case X: Y” : X presents the Xth test case and Y presents the minimum number of coins . If it is impossible to pay and receive exact change, output -1.Sample Input

3 70
5 25 50
5 2 1
0 0

Sample Output

 

Case 1: 3
题意:顾客需要v价值的物品,问,付款的硬币数最小是多少,给定n种硬币的价值和数量,当顾客付款超过v时,商家需要找钱给顾客,商家找的钱也计入硬币总数。题目中说明了商家可以找回任意价值的钱币,数量无限,需要注意题目提醒,顾客一次性付钱不超过20000.
思路:这道题如果按照平常把v价值的物品作为上限(也就是背包容量),会发现无法处理付款超过v时的情况,根据题目提示,顾客一次性付款不超过20000,我们可以将20000作为背包容量,在此背包容量下,可以计算v~20000任意价值的最小付款硬币量,因为不一定超过了给定的v,钱币数量就最大或者最小,我们需要在最后遍历比较得出最小值,ans = min(ans,dp1[i]+dp2[i-v]),dp1存的是顾客付款为v时的最小硬币数,dp2存的是商家找钱为i-v时的最小硬币数。注意dp1[0]和dp2[0]我们需要初始化为0,因为一开始硬币数为0。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define N 20010
int dp1[N],dp2[N],value[110],num[110];
int n,v,ans;
void CompletePack(int value)
{
    int i;
    for(i = value; i < N ; i ++)
        dp1[i] = min(dp1[i],dp1[i-value]+1);
    return;
}
void ZeroOnePack(int value,int num)
{
    int i;
    for(i = N-1; i >= value; i --)
        dp1[i] = min(dp1[i],dp1[i-value]+num);
    return;
}
int main()
{
    int i,j,k,x,t=0;
    while(scanf("%d%d",&n,&v),(n+v))
    {
        for(i = 1; i <= n; i ++)
            scanf("%d",&value[i]);//读入硬币价值 
        for(i = 1; i <= n; i ++)
            scanf("%d",&num[i]);//读入硬币数量 
        for(i = 0; i < N; i ++)
        {
            dp1[i] = inf;//初始化,因为我们所求的数量需要最小 
            dp2[i] = inf;
        }
        dp1[0] = dp2[0] = 0;//一开始初始化为0,数量为0 
        for(i = 1; i <= n; i ++)//对顾客来说,是一个多重背包的问题 
        {
            if(num[i]*value[i] > v)
                CompletePack(value[i]);
            else
            {
                k = 1;
                while(num[i]>0)
                {
                    x = min(k,num[i]);
                    ZeroOnePack(x*value[i],x);
                    num[i] -= x;
                    k*= 2;
                }
            }
        }
        for(i = 1; i <= n; i ++)//由题可知,商家的硬币数量是无限的,所以是完全背包 
            for(j = value[i]; j < N;j ++)
                dp2[j] = min(dp2[j],dp2[j-value[i]]+1);
        ans = inf;//我们需要最小值,所以先初始化为一个极大值 
        for(i = v; i < N; i ++)
            ans = min(ans,dp1[i]+dp2[i-v]);//顾客付款为i时,店家需要找钱i-v。 
        printf("Case %d: ",++t);
        if(ans == inf)
            printf("-1\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

 




以上是关于背包专题C - The trouble of Xiaoqian hdu3591混合背包:多重背包+完全背包的主要内容,如果未能解决你的问题,请参考以下文章

hdu 3591 The trouble of Xiaoqian

C. Coin Troubles 有依赖的背包 + 完全背包变形

Level of Qustion:Record the difficult level of Problem For future review

lesson 15 Fifty pence worth of trouble

背包DP专题

TOJ 1545Hurdles of 110m(背包题)