多重背包
多重背包二进制优化
模版先上
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 ) ; }
再来一多重背包题
#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; }