HDU 2844 Coins (多重背包->类01背包优化)
(TEST<31> 11.20)
解题思路
看着就是 多重背包问题 在这里 进行了
0/1背包的优化
用dp【价值】=所能达到的最大价值
来判定是否能够达到 这个 值
关于0/1背包优化 解析
(出自ACwing 基础算法视频第五章 第一节动态规划 )
看 1023 数字之和能够组成 1023? 0-1023 枚举每一个
显然 是暴力
如果将其分成几组的话
1,2,4,8…512 一共 10组 每组
这样 看错 0/1背包在每一组 dp【】更新的时候就会
遍历所有0-1023的多有值
组号 | 遍历范围 | 组内数字 | 组内遍历值 |
---|---|---|---|
第一组 | 0~1 | 1 | 0,1 |
第二组 | 0~3 | 2 | 2,3 |
第三组 | 0~7 | 4 | 4,5,6,7 |
… | … | … | … |
第十组 | 0~1023 | 512 | 512~1023 |
或许有人会问 会不会出现 dp[i]>i的情况
这种情况不会出现 ,dp[i]更新依赖于
dp[i]=max(dp[i],dp[i-value]+value);
这样每次更新 都依靠前面的值
最前的初始值 dp[0]=0;
又因为你值的更新程度就等于
你坐标变化的量所以不会超过。
AC 代码如下
#include<iostream>
#include <cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int v,w;
int val[105],num[105];
int dp[100000+5];
void pack(int value, int number){
//完全背包模型
if(value*number>=w){
for(int i=value; i<=w;i++){
dp[i]=max(dp[i],dp[i-value]+value);
}
}else{
//0/1背包模型
//优化 0/1背包
int k=1;
int nc=number;
while(k<nc){
for(int i=w;i>=k*value;i--)
dp[i]=max(dp[i],dp[i-k*value]+k*value);
nc-=k;
k*=2;
}
//优化0/1背包 ->遍历 优化2^k余下的硬币个数
for(int i=w;i>=nc*value;i--){
dp[i]=max(dp[i],dp[i-nc*value]+nc*value);
}
}
}
int main(){
while(~scanf("%d%d%",&v,&w)&&v&&w){
memset(dp,0,sizeof(dp));
for(int i=0;i<v;i++){
scanf("%d",&val[i]);
}
for(int i=0;i<v;i++){
scanf("%d",&num[i]);
}
for(int i=0;i<v;i++){
pack(val[i],num[i]);
}
int ans=0;
for(int i=1;i<=w;i++){
if(dp[i]==i)
ans++;
}
printf("%d\n",ans);
}
return 0;
}