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

The trouble of Xiaoqian

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2783    Accepted Submission(s): 967


Problem Description
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.
 

Input
There 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.
 

Output
Output 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
 

题意:

你要去商店买东西,但是规定你只能使用规定面额的硬币来支付(每种硬币的数量也是有规定的),售货员所持有规定面额的硬币无限个(用于找零),现在要计算怎样交易最少数量的硬币(包括你给售货员的和售货员找零给你的)来完成交易,注意:单笔交易不得超过20000元。 

分析:对卖家运用完全背包,对买家利用多重背包

代码(不知怎么的TLE了好多次):

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define mem(a) memset(a,0,sizeof(a))

using namespace std;

const int maxn = 20000 + 5 , inf = 0x3f3f3f3f ;
int dp1[maxn];//买家
int dp2[maxn];//卖家
int v[maxn],c[maxn];
int n,m;

void ZoreOnePack(int dp[],int cost ,int weight){//0 1 背包
    for(int j = maxn-1 ; j >= cost ; j -- )
        dp[j] = min(dp[j],dp[j-cost]+weight);
}

void CompletePack(int dp[],int cost,int weight){//完全背包
    for(int j = cost ; j < maxn ; j ++ )
        dp[j] = min(dp[j],dp[j-cost]+weight);
}

void MultiplePack(int dp[],int cost,int weight,int num){//多重背包
    if(num*cost>=maxn){//当总量大于或等于最大数量时,相反与完全背包
        CompletePack(dp,cost,weight);
        return;
    }
    int k = 1;
    while(k<num){//利用二进制优化为01背包
        ZoreOnePack(dp,k*cost,k*weight);
        num-=k;
        k*=2;
    }
    ZoreOnePack(dp,cost*num,num*weight);//剩下的
}

void init(){//初始化
    for(int i = 1 ; i< maxn ; i ++ ) dp1[i] = dp2[i] = inf;
    dp1[0] = dp2[0] = 0;
}

int main(){
    int iKase = 1;
    while(scanf("%d %d",&n,&m)!=EOF&&n&&m){

        init();

        for(int i = 0 ; i < n ; i ++ ) scanf("%d",&v[i]);
        for(int i = 0 ; i < n ; i ++ ) scanf("%d",&c[i]);

        for(int i = 0 ; i < n ; i ++ ) CompletePack(dp2,v[i],1);
        for(int i = 0 ; i < n ; i ++ ) MultiplePack(dp1,v[i],1,c[i]);

        int ans = inf ;
        //最后结果就是dp1[i]+dp2[i-m]
        for(int i = m ; i < maxn ; i ++ ){
            if(dp1[i]!=inf&&dp2[i-m]!=inf)
            ans = min(ans,dp1[i]+dp2[i-m]);
        }
        if(ans!=inf)
            printf("Case %d: %d\n",iKase++,ans);
        else
            printf("Case %d: -1\n",iKase++);
    }
    return 0 ;
}

阅读更多
个人分类: dp
上一篇动态规划入门——子序列问题
下一篇线段树模板题
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭