程式碼隨想錄演算法訓練營第四十六天| 139.單詞拆分 多重揹包 揹包問題總結篇!

SandaiYoung發表於2024-03-14

單詞拆分

題目連結:139. 單詞拆分 - 力扣(LeetCode)

思路:竟然真能轉化為揹包問題。

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> t(wordDict.begin(),wordDict.end());
        vector<bool> dp(s.size()+1,false);

        dp[0]=true;
        for(int i=1;i<=s.size();i++){
            for(int j=0;j<i;j++){
                string word=s.substr(j,i-j);//substr(起始位置,擷取個數)
                if(t.find(word)!=t.end()&&dp[j]){
                    dp[i]=true;
                }
            }
        }
        return dp[s.size()];

    }
};

關於多重揹包,你該瞭解這些!

多重揹包和01揹包的區別在於一件物品能用多次,且不是不限次。一種處理方法,是將可多次使用的物品當做不同的物品,因此將問題轉化為01揹包問題。如

for (int i = 0; i < n; i++) {
    while (nums[i] > 1) { // 物品數量不是一的,都展開
        weight.push_back(weight[i]);
        value.push_back(value[i]);
        nums[i]--;
    }
}

但這個方法由於vector的動態擴容十分耗時。還有一種處理方式,就是放到for迴圈裡再遍歷一輪

for(int i = 0; i < n; i++) { // 遍歷物品
        for(int j = bagWeight; j >= weight[i]; j--) { // 遍歷揹包容量
            // 以上為01揹包,然後加一個遍歷個數
            for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) { // 遍歷個數
                dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);
            }
        }
    }

揹包問題總結篇!

程式碼隨想錄 (programmercarl.com)

揹包遞推公式

  • 問能否能裝滿揹包(或者最多裝多少):dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
  • 問裝滿揹包有幾種方法:dp[j] += dp[j - nums[i]]
  • 問揹包裝滿最大價值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
  • 問裝滿揹包所有物品的最小個數:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

01揹包

二維dp陣列01揹包先遍歷物品還是先遍歷揹包都是可以的,且第二層for迴圈是從小到大遍歷。一維dp陣列01揹包只能先遍歷物品再遍歷揹包容量,且第二層for迴圈是從大到小遍歷。

完全揹包

純完全揹包的一維dp陣列實現,先遍歷物品還是先遍歷揹包都是可以的,且第二層for迴圈是從小到大遍歷。

但是僅僅是純完全揹包的遍歷順序是這樣的,題目稍有變化,兩個for迴圈的先後順序就不一樣了。

如果求組合數就是外層for迴圈遍歷物品,內層for遍歷揹包

如果求排列數就是外層for遍歷揹包,內層for迴圈遍歷物品

相關文章