SJTU OJ 1069 二哥的硬币

SJTU OJ 1069 二哥的硬币

原题链接

此题很久之前所写,觉得对于背包问题很有代表意义,就整理一下。
每个面值x的硬币看做价值w=x,占空间v=x的一个物品。根据同面值硬币总值是否超过m分为01背包和完全背包两类。最后判断体积i的背包是否最大能装i价值的硬币,即是否能凑成i面值。
代码如下:

#include 
#include 
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*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;
}

你可能感兴趣的:(SJTUOJ)