[leetcode] 0-1揹包問題詳解 416,474,1049題

格式化的代碼求解揹包問題

先驗: 《揹包九講》的pdf先熟悉一波

416.選擇子集和等於所有元素值和的一半
轉化: 0-1揹包恰好裝滿問題

/*
0-1揹包的恰好裝滿的問題
選擇若干物品,使得物品價值和  恰好等於sum(array)/2
揹包容量: sum(array)/2
重量花費cost: array[i]
物品價值: 0         本題: 也可以將"價值"設定爲array[i]

恰好裝滿: dp[0]=0, dp[1,...V]=INT_MIN
*/
#include "func.h"

int V = 0; //揹包體積
void zeroOnePack(vector<int>&F,int costi, int weighti){
    for(int i=V;i>=costi;i--)           //3. >=,逆序
        F[i] = std::max(F[i],F[i-costi]+weighti);
}
bool canPartition(vector<int>& array){
    int sum = 0;
    for(auto& i : array) sum += i;
    if(sum%2) return false;
    V = sum/2;
    vector<int> F(V+1,INT32_MIN);       //0.init V+1空間長度
    F[0] = 0;
    for(int i=0;i<array.size();i++)     //遍歷每一件物品
        zeroOnePack(F,array[i],0);      //1.zeroOnePack
    if(F.back() == INT32_MIN)  return false;
    else return true;
}

.
.
1049.兩兩的取石頭,碰撞後減去小的重量,最後1塊石頭時的"最小"重量
轉化: 0-1揹包不超過揹包體積下的最大重量

/*
兩兩的取石頭,碰撞後減去小的重量,最後1塊石頭時的"最小"重量
轉化0-1揹包:
揹包體積: sum(array)/2
重量費用:array[i]
價值:array[i]   本題:設定最大化的目標=重量

不超過揹包容量,計算石頭能佔據的最大"價值"  
F[0,...V] = 0
*/
#include "func.h"
// 0-1揹包遍歷物品個數&體積容量

int V = 0;
void zeroOnePack(vector<int>&F,int costi,int valuesi){
   for(int i=V;i>=costi;i--)
       F[i] = std::max(F[i],F[i-costi]+valuesi);
}
int lastStoneWeightII(vector<int>& array){
   int sum = 0;
   for(auto& i : array) sum+=i;
   V = (int)sum/2;
   vector<int> F(V+1,0);     //0.intit 空間長度V+1
   for(int i=0;i<array.size();i++)     //1.遍歷每一件物品
       zeroOnePack(F,array[i],array[i]);
   return sum - 2*F.back();
}

.
.
1049.給定vector,string只包含0或者1. 選取最大數量的string,使得0,1總數不超過指定數值
轉化:物品ith的二維費用問題 (並不是限定使用次數的多重揹包問題)

/*
給定vector<string>,string只包含0或者1. 選取最大數量的string,使得0,1總數不超過指定數值
物品: 字符串s1
費用1: s1中'0'的個數
費用2: s1中'1'的個數
容量1: '0'的個數限制V
容量2: '1'的個數限制U
價值: 1     題目要求: 最大化物品的數量

遍歷物品個數,容量(逆序)
物品ith有兩種費用,不是多重揹包問題。多重揹包:物品的使用次數不超過Mi次
*/
#include "func.h"

int V = 0;
int U = 0;
void zeroOnePack(vector<vector<int>>& F, int cost1,int cost2,int values){
    for(int i=V;i>=cost1;i--){
        for(int j=U;j>=cost2;j--)
            F[i][j] = std::max(F[i][j],
                                F[i-cost1][j-cost2] + values);      //二維費用更新
    }
}

vector<int> get_0_1_nums(string str){
    vector<int> ans(2,0);
    for(auto& i : str){
        if( i == '0') ans[0] += 1;
        else ans[1] += 1;
    }
    return ans;
}

int findMaxForm(vector<string>& strs,int m,int n){
    V = m;
    U = n;
    vector<vector<int>>F(V+1,vector<int>(U+1,0));  //init; 注意二維費用初始化***
    for(auto& str : strs) {
        vector<int> nums_0_1 = get_0_1_nums(str);
        zeroOnePack(F, nums_0_1[0], nums_0_1[1], 1);
    }
    return F[V][U];    
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章