SJTU OJ 1069 二哥的硬币
此题很久之前所写,觉得对于背包问题很有代表意义,就整理一下。
每个面值x的硬币看做价值w=x,占空间v=x的一个物品。根据同面值硬币总值是否超过m分为01背包和完全背包两类。最后判断体积i的背包是否最大能装i价值的硬币,即是否能凑成i面值。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int m, n;
int a[105];
int c[105];
int dp[100005];
int mmax(int x, int y){
return x>y ? x:y;
}
void complete_bag(int v, int w){
for (int i=v; i<=m; i++){
dp[i]= mmax(dp[i], dp[i-v]+w);
}
}
void zeroone_bag(int v, int w){
for (int i=m; i>=v; i--){
dp[i] = mmax(dp[i], dp[i-v]+w);
}
}
void multi_bag(int v, int w, int c){
if (v*c>=m){
complete_bag(v, w);
}
else{
int k=1;
while (k<c){
zeroone_bag(k*v, k*w);
c-=k;
k*=2;
}
zeroone_bag(c*v, c*w);
}
}
int main()
{
scanf("%d%d", &n, &m);
while (!(n == 0 && m == 0)){
for (int i=1; i<=n; i++){
scanf("%d", &a[i]);
}
for (int i=1; i<=n; i++){
scanf("%d", &c[i]);
}
for (int i=0; i<=m; i++){
dp[i] = 0;
}
for (int i=1; i<=n; i++){
multi_bag(a[i], a[i], c[i]);
}
int countn=0;
for (int i=1; i<=m; i++){
if (dp[i]==i){
countn++;
}
}
printf("%d\n", countn);
scanf("%d%d", &n, &m);
}
return 0;
}