一.题目描述
二. 解题思路
该题如果套用普通的多重背包问题那么会超时,因此我们必须降低时间复杂度。下面来介绍多重背包的二进制优化,优化后多重背包问题就转化为普通的01背包问题。
二进制拆分思想:
假设第i种物品有si件,将第i种物品拆分成若干件物品,每件物品的件数和价值乘以一个拆分系数(1,21,22,…,2k-1,si-(2k-1))。例如si=12,那么拆分系数就是1,2,4,5,转化成4件01背包的物品:(vi,wi),(2vi,2wi),(4vi,4wi),(5vi,5wi),那么就由原来的12件物品转化成为了4件物品,时间复杂度降低。
关键代码:
三. AC代码
#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
using namespace std;
#define MAX 100010
int V,type;
int value[1010];
int dp[MAX];
int main(){
int res=1;
int n,v;
while(cin>>V>>type){
memset(dp,0,sizeof(dp));
memset(value,0,sizeof(value));
for(int i=0;i<type;i++){
cin>>n>>v; //数量和面值
for(int j=1;j<=n;j=j*2){
value[res++]=j*v;
n-=j;
}
if(n){
value[res++]=n*v; //这里也必须是res++,因为不能保证最后是不是以一个不是2^k的数结束,WA的原因就是因为res后没加++
}
}
int ma=0;
for(int i=1;i<res;i++){
for(int j=V;j>=value[i];j--){
dp[j]=max(dp[j],dp[j-value[i]]+value[i]);
}
}
cout<<dp[V]<<endl;
}
}