HDU 2844 Coins (多重背包->类01背包优化) (TEST 11.20)

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;
}
发布了55 篇原创文章 · 获赞 1 · 访问量 972

猜你喜欢

转载自blog.csdn.net/weixin_43556527/article/details/103190772