完全揹包問題

在這裏插入圖片描述
在這裏插入圖片描述

方法:直接尋找遞推關係

在這裏插入圖片描述
i1i-1 件物品選 kk

int dp[maxn+1][maxn+1];
void solve(){
    for(int i=0;i<n;i++)
        for(int j=0;j<=W;j++)
            for(int k=0;k*w[i]<=j;k++)
                dp[i+1][j]=max(dp[i+1][j],dp[i][j-k*w[i]]+k*v[i]);
    cout<<dp[n][W];
}

k的循環最壞可能從0到W,所以算法時間複雜度爲 O(nW2)O(nW^2)

我們尋找這個算法中多餘的計算(已知結果的計算)
dp[i+1][j]的計算中選擇 k(k1)k(k≥1) 個的情況,與在dp[i+1][j-w[i]]的計算中選擇 k1k-1 個的情況是相同的,所以dp[i+1][j]的遞推中 k1k≥1 部分的計算已在dp[i+1][j-w[i]]的計算中完成了。則可按照如下方式變形:
在這裏插入圖片描述

void solve(){
    for(int i=0;i<n;i++)
        for(int j=0;j<=W;j++){
            if(i<w[i]) dp[i+1][j]=dp[i][j];
            else dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i]);
        }
    cout<<dp[n][W];
}

時間複雜度爲 O(nW)O(nW)。完全揹包問題也可以通過不斷重複利用一個數組來實現:

int dp[maxn+1];
void solve(){
    for(int i=0;i<n;i++)
        for(int j=0;j<=W;j++)
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);      
    cout<<dp[W];
}

DP數組的再利用

還可能通過將兩個數組滾動使用來實現重複利用。例如

dp[i+1][j]=max(do[i][j],dp[i+1][j-w[i]]+v[i])

這一遞推式中,dp[i+1]計算時只需要dp[i]dp[i+1],所以可以結合奇偶性寫成如下形式:

int dp[2][maxn+1];
void solve(){
    for(int i=0;i<n;i++)
        for(int j=W;j<=W;j++){
            if(j<w[i]) dp[(i+1)&1][j]=dp[i&1][j];
            else dp[(i+1)&1][j]=max(dp[i&1][j],dp[(i+1)&1][j-w[i]]+v[i]);
        }           
    cout<<dp[n&1][W];
}
發佈了120 篇原創文章 · 獲贊 63 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章