hdu 3591 The trouble of Xiaoqian

hdu 3591  The trouble of Xiaoqian

题意:xiaoqi要买一个T元的东西,当前的货币有N种,xiaoqi对于每种货币有Ci个;题中定义了最小数量即xiaoqi拿去买东西的钱的张数加上店家找的零钱的张数(店家每种货币有无限多张,且找零是按照最小的数量找零的);问xiaoqi买元东西的最小数量?

多重背包+完全背包;

思路:这个最小数量是拿去买东西的张数和找零的张数之和,其实我们只需要将这两个步骤分开,开算出能买T元东西的前i最少f[i]张,这里涉及到容量问题;容量只要大于T小于最大的上线20,000即可;之后使用贪心将货币排序加上找的零钱的数量,求出最小的数量即可;

注:无解的情况分为 总的和达不到T,和当前的货币不能找开i;(i - T找零时除到了0...RE了几次);

78MS  1668K

 

#include<bits/stdc++.h>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
#define inf 0x3f3f3f3f
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1|1
typedef __int64 ll;
template<typename T>
void read1(T &m)
{
    T x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    m = x*f;
}
template<typename T>
void read2(T &a,T &b){read1(a);read1(b);}
template<typename T>
void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
template<typename T>
void out(T a)
{
    if(a>9) out(a/10);
    putchar(a%10+'0');
}
const int M = 20020;
int f[M],V,n;
int w[110],num[110];
void ZeroOnePack(int w,int k)
{
    for(int v = V;v >= w;v--)
        f[v] = min(f[v],f[v-w]+k);
}
void CompletePack(int w)
{
    for(int v = w;v <= V;v++)
        f[v] = min(f[v],f[v-w]+1);
}
void MultiPack(int w,int num)
{
    if(w*num >= V)
        CompletePack(w);
    else{
        for(int k = 1;k < num;k <<= 1){
            ZeroOnePack(w*k,k);
            num -= k;
        }
        ZeroOnePack(w*num,num);
    }
}
inline int change(int a)
{
    int cnt = 0;
    for(int i = n;a;i--){
        if(w[i] == 0) return inf;
        cnt += a/w[i];
        a %= w[i];
    }
    return cnt;
}
int main()
{
    int t,kase = 1;
    while(scanf("%d%d",&n,&t) == 2 && n+t){
        int sum = 0;
        rep1(i,1,n) read1(w[i]);
        rep1(i,1,n) read1(num[i]),sum += num[i]*w[i];
        V = min(sum,M-1);
        memset(f,0x3f,sizeof(f));
        f[0] = 0;
        rep1(i,1,n)
            MultiPack(w[i],num[i]);
        sort(w+1,w+n+1);
        //rep_1(i,n,1) cout<<w[i]<<" ";puts("");
        int ans = inf;
        rep1(i,t,V)if(f[i] != inf){
            f[i] += change(i-t);
            ans = min(ans,f[i]);
        }
        printf("Case %d: %d\n",kase++,ans == inf?-1:ans);
    }
    return 0;
}
View Code

 

你可能感兴趣的:(hdu 3591 The trouble of Xiaoqian)