[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只包含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];    
}

你可能感兴趣的:(Leetcode)