POJ 1014 && HDU 1059 Dividing(完全背包问题)

Description
有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,使得两份的总价值相等
Input
多组输入,每组用例占一行包括六个整数表示这六种物品的数量,以0 0 0 0 0 0结束输入
Output
对于每组用例,输出是否能将这些物品分为价值相同的两份
Sample Input
1 0 1 2 0 0
1 0 0 0 1 1
0 0 0 0 0 0
Sample Output
Collection #1:
Can’t be divided.
Collection #2:
Can be divided.
Solution
统计总价值sum,问题转化为背包容量为sum/2的完全背包问题,套模版即可
Code

#include<stdio.h>
#include<string.h>
#define max(x,y) ((x)>(y)?(x):(y))
int dp[111111],num[7],v,flag;
void Complete_Pack(int cost,int weight)
{
    for(int i=cost;i<=v;i++)
    {
        dp[i]=max(dp[i],dp[i-cost]+weight);
        if(dp[i]==v)//剪枝 
        {
            flag=1;
            return ;
        }
    }          
    return ;
}
void ZeroOne_Pack(int cost,int weight)
{
    for(int i=v;i>=cost;i--)
    {
        dp[i]=max(dp[i],dp[i-cost]+weight);
        if(dp[i]==v)//剪枝 
        {
            flag=1;
            return ;
        }
    }
    return ;
}
void Multiple_Pack(int cost,int weight,int amount)
{
    if(cost*amount>=v)
    {
        Complete_Pack(cost,weight);
        return;
    }
    if(flag) return ;//剪枝 
    int k=1;
    while(k<amount)
    {
        ZeroOne_Pack(k*cost,k*weight);
        if(flag) return ;//剪枝 
        amount-=k;
        k*=2;
    }
    ZeroOne_Pack(amount*cost,amount*weight);
    return ;
}
int main()
{
    int res=1;
    while(scanf("%d%d%d%d%d%d",&num[1],&num[2],&num[3],&num[4],&num[5],&num[6]))
    {
        int sum=0;
        for(int i=1;i<=6;i++)
            sum+=i*num[i];
        if(!sum)break;
        memset(dp,-1,sizeof(dp));//初始化 
        dp[0]=0;
        flag=0;
        v=sum/2;//背包容量为总价值的一半 
        if(sum%2==0)
            for(int i=1;i<=6;i++)
            {
                Multiple_Pack(i,i,num[i]);//多重背包 
                if(flag) break;//剪枝 
            }
        printf("Collection #%d:\n",res++);
        if(flag)printf("Can be divided.\n\n");
        else printf("Can't be divided.\n\n"); 
    }
    return 0;
}

你可能感兴趣的:(POJ 1014 && HDU 1059 Dividing(完全背包问题))