動態規劃-揹包問題

0-1揹包

N件物品,揹包最大容量爲V, 第i件物品的費用爲w[i],價值爲v[i]
使用f[i][j]表示在容量爲j,在前i件物品中(包括i)選擇物品所得到的最大價值
遞推方程爲f[i][j] = max(f[i-1][j], f[i-1][j - w[i]] + v[i]) 在是否選擇第i件物品取最大值
從後往前更新就可使用一維數組簡化f[j] = max(f[j], f[j-w[i]] + v[i])
416. Partition Equal Subset Sum數組

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = accumulate(nums.begin(), nums.end(), 0);
        return sum & 1 ? false : subSum(nums, sum >> 1);
    }
    
    bool subSum(vector<int>& nums, int s){
        bool dp[s + 1] = {false};
        dp[0] = true;
        for(int n : nums){
            for(int i = s; i >=n; i--){
                dp[i] = dp [i] || dp[i - n];
            }
        }
        
        return dp[s];
    }
    
};

徹底揹包

每種物品無限件, 遞推方程爲
f[i][v]=max(f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v)
322. Coin Change優化

//超時
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
   
        if(amount == 0) return 0;
        vector<vector<int>> f(n+1, vector<int>(amount+1, amount + 1));
        
        for(int i = 0; i < n; i++){
            f[i][0] = 0;
            for(int j = 1; j <= amount; j++){
                for(int k = 0; k * coins[i] <= j; k++){
                    f[i+1][j] = min(f[i+1][j], f[i][j - k * coins[i]] + k);
                }
            }
        }
        
        return f[n][amount] < amount + 1 ? f[n][amount] : -1;
    }
};

優化時間,三重循環變爲兩重循環, 注意這兩重循環可交換code

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
   
        if(amount == 0) return 0;
        vector<vector<int>> f(n+1, vector<int>(amount+1, amount + 1));
        for(int i = 0; i <= n; i++) f[i][0] = 0;
        for(int j = 1; j <= amount; j++){
            for(int i = 0; i < n; i++){
                
                if(j - coins[i] >= 0)
                    f[i+1][j] = min(f[i][j], f[i+1][j - coins[i]] + 1);
                else f[i+1][j] = f[i][j];
                
            }
        }
        
        return f[n][amount] < amount + 1 ? f[n][amount] : -1;
    }
};

優化空間,二維數組變爲一維數組leetcode

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
   
        if(amount == 0) return 0;
        vector<int> f(amount+1, amount + 1);
        f[0] = 0;
        for(int j = 1; j <= amount; j++){
            for(int i = 0; i < n; i++){
          
                if(j - coins[i] >= 0)
                    f[j] = min(f[j], f[j - coins[i]] + 1);

            }
        }
        
        return f[amount] < amount + 1 ? f[amount] : -1;
    }
};

518. Coin Change 2
作題的時候仍是要寫個二維的驗證一下get

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        int n = coins.size();
        vector<int> dp(amount + 1, 0);
        dp[0] = 1;
        
        for(int i = 0; i < n; i++){
            for(int j = coins[i]; j <= amount; j++){
                dp[j] += dp[j - coins[i]];
                // dp[i+1][j] = dp[i][j] + dp[i+1][j - coins[i]]
            }
        }
        
        return dp[amount];
    }
};

多重揹包

初始化問題

理解合法狀態,要看清題目中說的是正好放滿揹包,仍是最多放滿揹包
前者對應dp[i][0] = 0, dp[i][j] = INF(j != 0, 不是合法狀態),後者對應dp[i][0] = 0(全是合法狀態)it

參考

揹包九講io

相關文章
相關標籤/搜索