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的商品时, 他给售货员的硬币数目+售货员找他的硬币数目最少等于多少?

分析:

我们令dp1[j]==x表示小杰给售货员价值j的硬币时, 须要最少x个硬币. 我们令dp2[j]==x表示售货员给小杰价值j的硬币时, 须要最少x个硬币.

那么前一个问题就是一个多重背包问题(由于小杰的硬币有限度), 而第2个问题是全然背包问题(售货员硬币无限).

终于我们所求为:  min( dp1[T+i]+dp2[i]) 当中 i属于[0,20000-T].

对于第一个多重背包问题:

我们令dp1[i][j]==x表示用前i种硬币构成j金钱时, 最少须要x个硬币.

初始化: dp1全为INF且dp1[0][0]=0.

对于第i种硬币, 我们要分情况处理:

假设val[i]*num[i]>=20000, 那么就做一次全然背包.

假设val[i]*num[i]<20000, 那么就把该物品看出新的k+1种物品,然后做k+1次01背包.

终于我们所求为dp1[n][j]这维数组就是我们之前说的dp1[j].

对于第二个全然背包问题:

我们令dp2[i][j]==x表示用前i种硬币构成j金钱时, 最少须要x个硬币.

初始化: dp2全为INF 且dp2[0][0]=0.

状态转移: dp2[i][j] = min( dp2[i-1][j] , dp2[i][j-val[i]]+1 )     //sum是求和

前者表示第i种货币一个都不用, 后者表示第i种货币至少用1个.

终于所求: dp2[n][j]这维数组是我们上面所求的dp2[j].

终于让i从T+1到20000遍历一边, 找出min( dp1[T] , dp1[i]+dp2[i-T] )的值.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 1e8
const int maxn=100+5;

int n;//n种货币
int T;//商品金额
int val[maxn];//每种货币面值
int num[maxn];//每种货币数目
int dp1[20000+5];
int dp2[20000+5];

//1次01背包过程
void ZERO_ONE_PACK(int *dp,int cost,int sum)
{
    for(int i=20000;i>=cost;i--)
        dp[i] = min(dp[i],dp[i-cost]+sum);//注意这里是+sum,而不是+1
}

//1次全然背包过程
void COMPLETE_PACK(int *dp,int cost)
{
    for(int i=cost;i<=20000;i++)
        dp[i] = min(dp[i],dp[i-cost]+1);
}

//1次多重背包过程
void MULTIPLY_PACK(int *dp,int cost,int sum)
{
    if(cost*sum>=20000)
    {
        COMPLETE_PACK(dp,cost);
        return ;
    }

    int k=1;
    while(k<sum)
    {
        ZERO_ONE_PACK(dp,cost*k,k);
        sum-=k;
        k*=2;
    }
    ZERO_ONE_PACK(dp,cost*sum,sum);
}

int main()
{
    int kase=0;
    while(scanf("%d%d",&n,&T)==2)
    {
        //注意退出,否则WA
        if(n==0 && T==0) break;

        //读取输入
        for(int i=1;i<=n;i++)
            scanf("%d",&val[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&num[i]);

        //初始化
        for(int i=0;i<=20000;i++)
            dp1[i]=dp2[i]=INF;
        dp1[0]=dp2[0]=0;

        //递推
        for(int i=1;i<=n;i++)
            MULTIPLY_PACK(dp1,val[i],num[i]);
        for(int i=1;i<=n;i++)
            COMPLETE_PACK(dp2,val[i]);

        //输出结果
        int ans=dp1[T];
        for(int i=T+1;i<=20000;i++)
            ans=min(ans, dp1[i]+dp2[i-T]);

        printf("Case %d: %d\n",++kase,ans==INF?-1:ans);
    }
    return 0;
}
时间: 2024-12-30 04:01:55

HDU 3591 The trouble of Xiaoqian(多重背包+全然背包)的相关文章

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(多重背包)

#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

hdu 3591 The trouble of Xiaoqian

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

POJ 3260 The Fewest Coins(多重背包+全然背包)

http://poj.org/problem?id=3260 题意: John要去买价值为m的商品. 如今的货币系统有n种货币,相应面值为val[1],val[2]-val[n]. 然后他身上每种货币有num[i]个. John必须付给售货员>=m的金钱, 然后售货员会用最少的货币数量找钱给John. 问你John的交易过程中, 他给售货员的货币数目+售货员找钱给他的货币数目 的和最小值是多少? 分析: 本题与POJ 1252类型: http://blog.csdn.net/u013480600

【背包专题】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

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 (完全背包+二进制优化的多重背包)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3591 The trouble of Xiaoqian Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2798    Accepted Submission(s): 972 Problem Description In the countr

B 维背包+完全背包 Hdu2159

<span style="color:#3333ff;">/* ------------------------------------------------------------------------------------------------ author : Grant Yuan time : 2014.7.19 aldorithm: 二维背包+全然背包 ----------------------------------------------------

hdu 3591 多重加完全DP

题目: The trouble of Xiaoqian Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1997    Accepted Submission(s): 711 Problem Description In the country of ALPC , Xiaoqian is a very famous mathematici