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; }