POJ3260 完全背包 + 多重背包 xingxing在努力
这道题的意思是一个人有一定数额的银币若干个, 想用这些硬币买一些东西, 售货员会找零,现在问你如何用最少的银币买到东西。。。 先用完全背包预处理找零j块钱的时候最少需要多少硬币,然后用多重背包处理付款j块钱的时候最少需要多少银币, 最后将两个加起来就行。注意数组开大点。代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int inf = 0x3f3f3f3f; int N, T; int V[100 + 10]; //硬币的面额 int C[100 + 10]; //硬币的数量 int back[30000 + 10]; //找零为j是需要的最少的银币的数量 int f[30000 + 10]; //付款为j时所需要的最少的银币数量 void ComplatePack(int cost, int weight) { for(int j=cost; j<=30000; j++) if(f[j]>f[j-cost]+weight && f[j-cost]!=inf) f[j] = f[j-cost] + weight; return ; } void ZeroOnePack(int cost, int weight) { for(int j=30000; j>=cost; j--) if(f[j]>f[j-cost]+weight && f[j-cost]!=inf) f[j] = f[j-cost] + weight; return ; } void MultiPack(int cost ,int weight, int number) { if(cost*number>30000) { ComplatePack(cost, weight); return ; } int k = 1; while(k < number) { ZeroOnePack(k*cost, k*weight); number -= k; k *= 2; } ZeroOnePack(number*cost, number*weight); } int main() { while(scanf("%d%d", &N, &T) == 2) { for(int i=0; i<N; i++) scanf("%d", &V[i]); for(int i=0; i<N; i++) scanf("%d", &C[i]); memset(back, 0x3f, sizeof(back)); back[0] = 0; for(int i=0; i<N; i++) //预处理找零为j时所需银币最少 for(int j=V[i]; j<=30000; j++) if(back[j]>back[j-V[i]]+1 && back[j-V[i]]!=inf) back[j] = back[j-V[i]] + 1; memset(f, 0x3f, sizeof(f)); f[0] = 0; for(int i=0; i<N; i++) MultiPack(V[i], 1, C[i]); int res = inf; for(int i=T; i<=30000; i++) { if(back[i-T]!=inf&&f[i]!=inf&&back[i-T]+f[i]<res) res = back[i-T] + f[i]; } if(res == inf) printf("-1\n"); else printf("%d\n", res); } return 0; }