http://acm.hdu.edu.cn/showproblem.php?pid=1059

基础的二进制优化的多重背包

View Code
#include <iostream>
using namespace std ;
int V ;
int dp[200001] ;
void ZeroOnePack(int c,int w)
{
    for(int i=V;i>=c;i--)
        dp[i]=max(dp[i],dp[i-c]+w) ;
    return ;
}
void CompletePack(int c,int w)
{
    for(int i=c;i<=V;i++)
        dp[i]=max(dp[i],dp[i-c]+w) ;
    return ;
}
void MultiplePack(int c,int w,int a)
{
    if(c*a>=V)
    {
        CompletePack(c,w) ;
        return ;
    }
    int k=1 ;
    while(k<a)
    {
        ZeroOnePack(k*c,k*w) ;
        a-=k ;
        k<<=1 ;
    }
    ZeroOnePack(a*c,a*w) ;
}

int main()
{
    int n[7] ;
    int nCase=1 ;
    while(scanf("%d%d%d%d%d%d",&n[0],&n[1],&n[2],&n[3],&n[4],&n[5]))
    {
        V=n[0]+2*n[1]+3*n[2]+4*n[3]+5*n[4]+6*n[5] ;
        if(!V)
            break ;
        if(V&1)
        {
            printf("Collection #%d:\nCan't be divided.\n\n",nCase++) ;
            continue ;
        }
        memset(dp,0,sizeof(dp)) ;
        V>>=1 ;
        for(int i=0;i<6;i++)
            MultiplePack(i+1,i+1,n[i]) ;
        if(dp[V]==V)//一半容量的背包恰好能装下一半的东西 
            printf("Collection #%d:\nCan be divided.\n\n",nCase++) ;
        else
            printf("Collection #%d:\nCan't be divided.\n\n",nCase++) ;
    }
    return 0 ;
}