HDOJ1059(多重背包)

1.解法一:多重背包

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX(a,b) (a>b)?a:b
const int SIZE=500000+16;
int dp[SIZE];
int bag[7];
int nLimit;

void ZeroOnePack(int cost, int value)
{
    for(int i=nLimit; i>=cost; i--)
        dp[i]=MAX(dp[i],dp[i-cost]+value);
}

void CompletePack(int cost, int value)
{
    for(int i=cost; i<=nLimit; i++)
        dp[i]=MAX(dp[i],dp[i-cost]+value);
}

void MultiplyPack(int cost, int value, int amount)
{
    if(amount*cost>=nLimit) CompletePack(cost,value);
    else
    {
        int k=1;
        while(k<amount)
        {
            ZeroOnePack(k*cost, k*value);
            amount-=k;
            k<<=1;
        }
        
        ZeroOnePack(amount*cost,amount*value);
    }
}

bool CheckFinish()
{
    for(int i=1;i<=6;i++)
        if(bag[i]!=0)
            return false;
    return true;
}

int main()
{
    int T=0;
    while(true)
    {
        int sum=0;
        for(int i=1; i<=6; i++)
        {
            scanf("%d",&bag[i]);
            sum+=bag[i]*i;
        }
        if(CheckFinish())
            break;
            
        printf("Collection #%d:
",++T);
        if(sum%2==1)
        {
            printf("Can't be divided.
");
        }
        else
        {
            memset(dp,0,sizeof(dp));
            nLimit=sum/2;
            for(int i=1;i<=6;i++)
            {
                MultiplyPack(i,i,bag[i]);
            }
            if(dp[nLimit]==nLimit)
                printf("Can be divided.
");
            else
                printf("Can't be divided.
");
        }
        printf("
");
        
    }

    return 0;
}

2.解法二:多重部分和

#include<cstdio>
#include<cstring>
using namespace std;
const int SIZE=120000+16;
int a[6];
int dp[SIZE];
bool check()
{
    for(int i=0;i<6;i++)
        if(a[i]!=0)
            return true;
    return false;
}
int sum;

int main()
{
    int t=0;
    while(true)
    {
        sum=0;
        for(int i=0;i<6;i++)
        {
            scanf("%d",&a[i]);
            sum+=(i+1)*a[i];
        }
        if(!check())
            break;    
        
        printf("Collection #%d:
",++t);    
        if(sum%2==1)
        {
            printf("Can't be divided.
");
        }
        else
        {
            memset(dp,-1,sizeof(dp));
            int k=sum/2;
            dp[0]=0;
            for(int i=0;i<6;i++)
            {    
                for(int j=0;j<=k;j++)
                {
                    if(dp[j]>=0)
                    {
                        dp[j]=a[i];
                    }
                    else if(j<(i+1)||dp[j-(i+1)]<=0)
                    {
                        dp[j]=-1;    
                    }
                    else
                    {
                        dp[j]=dp[j-(i+1)]-1;
                    }            
                }
            }
            if(dp[k]>=0)
            {
                printf("Can be divided.
");
            }
            else
            {
                printf("Can't be divided.
");
            }
        }
        printf("
");
    }
    return 0;
}

 3.解法三:判断多重背包可否装满

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX(a,b) (a>b)?a:b
const int SIZE=500000+16;
const int INF=100000;
int dp[SIZE];
int bag[7];
int nLimit;
bool CheckFinish()
{
    for(int i=1;i<=6;i++)
        if(bag[i]!=0)
            return false;
    return true;
}

int main()
{
    int T=0;
    while(true)
    {
        int sum=0;
        for(int i=1; i<=6; i++)
        {
            scanf("%d",&bag[i]);
            sum+=bag[i]*i;
        }
        if(CheckFinish())
            break;
            
        printf("Collection #%d:
",++T);
        if(sum%2==1)
        {
            printf("Can't be divided.
");
        }
        else
        {
            nLimit=sum/2;
            memset(dp,0,sizeof(dp));
            dp[0]=1;
            int dpt[120000];
            for(int i=1;i<=6;i++)
            {
                memset(dpt,0,sizeof(dpt));
                for(int j=i;j<=nLimit;j++)
                    if(!dp[j]&&dp[j-i]&&dpt[j-i]<bag[i])
                    {
                        dpt[j]=dpt[j-i]+1;
                        dp[j]=1;
                    }
            }
            
            if(dp[nLimit])
            {
                printf("Can be divided.
");
            }
            else
            {
                printf("Can't be divided.
");
            }
        }
        
        printf("
");
    }

    return 0;
}

判断模板:
 

memset(dp,0,sizeof(dp));
dp[0]=1;
int used[120000];
for(int i=1;i<=nKind;i++)
{
    memset(used,0,sizeof(used));
    for(int j=weight[i];j<=nLimit;j++)
        if(!dp[j]&&dp[j-weight[i]]&&used[j-weight[i]]<bag[i])
        {
            used[j]=used[j-weight[i]]+1;
            dp[j]=1;
        }
}
原文地址:https://www.cnblogs.com/program-ccc/p/4705379.html