1. 程式人生 > >【背包專題】C - The trouble of Xiaoqian hdu3591【混合背包:多重背包+完全背包】

【背包專題】C - The trouble of Xiaoqian hdu3591【混合背包:多重背包+完全背包】

back 無法 name spa int receive with out man

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【混合背包:多重背包+完全背包】