【背包专题】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;
}
				
时间: 2024-11-05 04:38:10

【背包专题】C - The trouble of Xiaoqian hdu3591【混合背包:多重背包+完全背包】的相关文章

HDU3591 The trouble of Xiaoqian

这题一看 就知道 是 完全背包和多重背包的结合题目了; 对于买东西的是多重背包,商店是完全背包; 这里要用到背包的初始化问题,因为求最小,所以初值要尽量大,大于所有可能的最大值; 值得一提的是背包上限是20000,不是读入的T; 用两个数组分别记录需要用到的最少货币数,一维就够用了; 多重的单调队列好难不懂..只会用二进制优化过的多重背包; 下面给出代码: #include<iostream> #include<algorithm> #define maxn 100010 #def

HDU 3591 The trouble of Xiaoqian(多重背包+01背包)

HDU 3591 The trouble of Xiaoqian(多重背包+01背包) http://acm.hdu.edu.cn/showproblem.php?pid=3591 题意: 有一个具有n种货币的货币系统, 每种货币的面值为val[i]. 现在小杰手上拿着num[1],num[2],-num[n]个第1种,第2种-第n种货币去买价值为T(T<=20000)的商品, 他给售货员总价值>=T的货币,然后售货员(可能,如果小杰给的钱>T, 那肯定找钱)找钱给他. 售货员每次总是用

hdu 3591 The trouble of Xiaoqian

hdu 3591  The trouble of Xiaoqian 题意:xiaoqi要买一个T元的东西,当前的货币有N种,xiaoqi对于每种货币有Ci个:题中定义了最小数量即xiaoqi拿去买东西的钱的张数加上店家找的零钱的张数(店家每种货币有无限多张,且找零是按照最小的数量找零的):问xiaoqi买元东西的最小数量? 多重背包+完全背包: 思路:这个最小数量是拿去买东西的张数和找零的张数之和,其实我们只需要将这两个步骤分开,开算出能买T元东西的前i最少f[i]张,这里涉及到容量问题:容量只

HDU-3591 混合背包

The trouble of Xiaoqian Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2277    Accepted Submission(s): 805 Problem Description In the country of ALPC , Xiaoqian is a very famous mathematician.

【背包专题】G - Dividing hdu 1059【多重背包】

Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could just split the colle

混合三种背包问题(背包九讲)

问题: 如果将P01.P02.P03混合起来.也就是说,有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包).应该怎么求解呢? 01背包与完全背包的混合: 考虑到在P01和P02中给出的伪代码只有一处不同,故如果只有两类物品:一类物品只能取一次,另一类物品可以取无限次,那么只需在对每个物品应用转移方程时,根据物品的类别选用顺序或逆序的循环即可,复杂度是O(VN).伪代码如下: for i=1..N if 第i件物品属于01背包 for v

hdu3591The trouble of Xiaoqian 多重背包+完全背包

//给出Xiaoqian的钱币的价值和其身上有的每种钱的个数 //商家的每种钱的个数是无穷,xiaoqian一次最多付20000 //问怎样付钱交易中钱币的个数最少 //Xiaoqian是多重背包 //商家是完全背包 #include<cstdio> #include<cstring> #include<iostream> using namespace std ; const int maxn = 20010 ; const int inf = 0x3f3f3f3f

HDU 3591 The trouble of Xiaoqian(多重背包+全然背包)

http://acm.hdu.edu.cn/showproblem.php? pid=3591 题意: 有一个具有n种货币的货币系统, 每种货币的面值为val[i]. 如今小杰手上拿着num[1],num[2],-num[n]个第1种,第2种-第n种货币去买价值为T(T<=20000)的商品, 他给售货员总价值>=T的货币,然后售货员(可能,假设小杰给的钱>T,那肯定找钱)找钱给他. 售货员每次总是用最少的硬币去找钱给小杰. 如今的问题是: 小杰买价值T的商品时, 他给售货员的硬币数目+

hdu 3591 The trouble of Xiaoqian(多重背包)

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; int v[200],c[200]; int dp[30000]; int main() { int n,t; int i,j,k; int cas=1; while(scanf("%d%d",&n