POJ1276 Cash Machine(多重背包问题)


三种解法:多重背包转化为完全背包和01背包;多重背包通过二进制化化为01背包;通过计数法优化为2重循环。


code1:         47MS 

#include <cstdio>
#include <cstring>
#define Max(a,b) (a) >(b)?(a):(b)
int dp[100005], Cost[11], Count[11], cash;

void ZeroOnePack(int cost)
{
    int i;
    for(i=cash; i>=cost; --i)
        dp[i] = Max(dp[i], dp[i-cost]+cost);
}

void CompletePack(int cost)
{
    int i;
    for(i=cost; i<=cash; ++i)
        dp[i] = Max(dp[i], dp[i-cost]+cost);
}

void MultiplePack(int cost, int count)
{
    if(cost*count > cash)
        CompletePack(cost);
    else
    {
        int k=1;
        while(k < count)
        {
            ZeroOnePack(k*cost);
            count -= k;
            k <<=1;
        }
        ZeroOnePack(count*cost);
    }
}

int main()
{
    int n, i, j, k;
    while(~scanf("%d%d",&cash,&n))
    {
        for(i=1; i<=n; ++i)
            scanf("%d%d",&Count[i],&Cost[i]);
        memset(dp, 0, sizeof dp );
        for(i=1; i<=n; ++i)
            MultiplePack(Cost[i], Count[i]);
        printf("%d\n", dp[cash]);
    }
    return 0;
}


code2:       110MS

#include <cstdio>
#include <cstring>
#define Max(a,b) (a) >(b) ? (a):(b)
int dp[100010];
int  n[230], w[230], v, N;
int b[11] = {1,2,4,8,16,32,64,128,256,512,1024};

int main()
{
    int i, j, cash, Count, k;
    int nn, ww;
    while(~scanf("%d%d",&cash,&N)) {
        Count = 1;
        for(i=1; i<=N; ++i) {
            scanf("%d%d",&nn,&ww);
            if(nn!=0) {
                for(j=10; j>=0; --j)
                    if(nn-b[j]+1>0)
                        break;
                for(k=0; k<=j-1; ++k) {
                    n[Count] = b[k];
                    w[Count] = ww*b[k];
                    Count++;
                }
                n[Count] = nn-b[j]+1;
                w[Count]=ww*(nn-b[j]+1);
                Count++;
            }
        }
        Count--;
        memset(dp, 0, sizeof dp );
        for(i=1; i<=Count; ++i)
            for(v=cash; v>=0; --v)
                if(v-w[i]>=0)
                    dp[v] = Max(dp[v], dp[v-w[i]] + w[i]);
        printf("%d\n", dp[cash]);
    }
    return 0;
}


code3:   16MS

//1、可以采有计数的方法代替单调队列将时间复杂度降到o(vn) 
//注:计数的这种方法解决多重背包时有限制,只能解决体积与价值相等的情况

#include <cstdio>
#include <cstring>

int main()
{
    int i, j, cash, n, v[15], nums[15];
    int opt[100010];
    int cnt[100010];
    while(~scanf("%d%d",&cash,&n)) {
        for(i=0; i<n; ++i)
            scanf("%d%d",&nums[i],&v[i]);
        for(i=0; i<=cash; ++i)
            opt[i] = 0;
        for(i=0; i<n; ++i) {
            memset(cnt, 0, sizeof(int)*(cash+1));
            for(j=v[i]; j<=cash; ++j) {
                if(opt[j] <opt[j-v[i]]+v[i]&&cnt[j-v[i]]<nums[i]) {
                    cnt[j] = cnt[j-v[i]]+1;
                    opt[j] = opt[j-v[i]] + v[i];
                }
            }
        }
        printf("%d\n",opt[cash]);
    }
    return 0;
}



你可能感兴趣的:(POJ1276 Cash Machine(多重背包问题))