多重背包

多重背包二进制优化

模版先上

int dp[N];
void OneZeroPack( int v , int n , int w ){
      for( int i = v ; i >= n ; i-- )
            dp[i] = max( dp[i] , dp[i-n] +w ) ;
}
void CompletePack( int v , int n , int w ){
      for( int i = n ; i <= v ; i++ )
            dp[i] = max( dp[i] , dp[i-n] +w ) ;
}
void MultipliePack( int v , int c, int w , int n){
      if( n*c >= v ){
            CompletePack( v , c , w ) ;
            return ;
      }
      int k = 1 ;
      while( k < n ){
            OneZeroPack( v , k*c , k*w ) ;
            n -= k ;
            k =k<<1 ;
      }
      OneZeroPack( v , n*c , n*w ) ;
}

再来一多重背包题

hdu-1059-Dividing

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 60006
using namespace std;
int V,num[7],dp[MAXN];
void OneZeroPack(int c){  //01背包
    for(int i=V;i>=c;i--){
        dp[i]=max(dp[i],dp[i-c]+c);
    }
}
void CompeletePack(int c){  //完全背包
    for(int i=c;i<=V;i++){
        dp[i]=max(dp[i],dp[i-c]+c);
    }
}
void MultiplePack(){    //多重背包
    for(int i=1;i<=6;i++){
        if(i*num[i]>=V)
        CompeletePack(i);
        else{
            int k=1;
            while(k<num[i]){   //二进制优化
                OneZeroPack(i*k);
                num[i]=num[i]-k;
                k=k<<1;
            }
            OneZeroPack(num[i]*i);
        }
    }
}
int main()
{
    int cas=1;
    while(true){
        V=0;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=6;i++){
        scanf("%d",&num[i]);
        V+=num[i]*i;
        }
        if(!V)break;
        printf("Collection #%d:\n",cas++);
        if(V&1)printf("Can't be divided.\n\n");
        else{
            V=V/2;
            MultiplePack();
            if(dp[V]==V)
            printf("Can be divided.\n\n");
            else
            printf("Can't be divided.\n\n");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/arbitrary/p/2644675.html