天天看點

HDU 2844 Coins (多重背包->類01背包優化)

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;
}