参考
代码随想录
题目一:LeetCode 1049. 最后一块石头的重量 II
这个题和之前的“416 分割等和子集”非常的类似,如果给出的stones[]数组能被分成相等的两个数组,那么剩余石头的最小重量就是0。求解思路和分割等和子集一样,只是最后的返回值不同。套用01背包,物品的重量和价值都是stones[]。
- 确定dp数组及其下标的含义
 dp[j] :背包最大承载重量j得到的最大价值为dp[j],对应本题,最大总和j对应的实际能达到的最大总和为dp[j]。
- 确定递推关系
 一维dp数组01背包的递推公式如下:
dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
- dp数组初始化
 题目中给出1 <= stones[i] <= 100,因此dp数组全部初始化为0。
- 确定遍历顺序
 遍历顺序在一维dp数组01背包中已经分析过了,如下:
for(int i = 0; i < stones.size(); i++){
    for(int j = target; j >= stones[i]; j--){
        dp[j] = max(dp[j],dp[j - stones[i]] + stones[i]);
    }
}
- 举例推导dp数组
 以stones = [2,4,1,1]为例,推导得到的dp数组如下:
  
整体代码实现如下:
class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum = 0;
        for(int i = 0; i < stones.size(); i++)  
            sum += stones[i];
        int target = sum / 2;
        vector<int> dp(target+1,0);
        for(int i = 0; i < stones.size(); i++){
            for(int j = target; j >= stones[i]; j--){
                dp[j] = max(dp[j],dp[j - stones[i]] + stones[i]);
            }
        }
        return sum - dp[target] * 2;
    }
};
题目二:LeetCode 494. 目标和
假设添加“+”或者“-”之后,加法总和为x,则减法总和为sum-x(注意这里指的是添加减号的那些数的总和),其中sum是添加符号之前的数组总和,则有
target = x + (-(sum-x)) = 2x-sum
因此可以得到x的表达式:
x = (sum + target) / 2
因此将问题转化为数组中有多少种和为x的组合,套用01背包,就是装满容量为x的背包,有多少种方法,此时的背包容量bagSize就是这里的x。
 因为给定的元素都为整数,所以如果sum+target为奇数的话是不可能得到和为x的组合的,因为奇数除以2之后结果会被截断。
- 明确dp数组及其下标的含义
 dp[j]:装满容量为j的背包有dp[j]种方法
- 确定递推公式
 对于数组中的某一个元素nums[i],得到dp[j]可以有dp[j - nums[i]]种方法,而nums[i]可以是数组中满足条件的任一个数,因此可以得到递推公式:
dp[j] += dp[j - nums[i]]
- 初始化dp数组
 dp[0] = 1,其他初始化为0
- 确定遍历顺序
 nums放在外循环,target在内循环,且内循环倒序。
- 举例推导递推公式
 nums = [1,1,1,1,1],target = 3
  
 完整的代码实现如下:
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for(int i = 0; i < nums.size(); i++)
            sum += nums[i];
        if((sum + target) % 2 == 1) return 0;
        if(sum < abs(target))    return 0;
        int bagSize = (sum + target) / 2;
        vector<int> dp(bagSize+1,0);
        dp[0] = 1;
        for(int i = 0; i < nums.size(); i++){
            for(int j = bagSize; j >= nums[i]; j--){
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[bagSize];
    }
};
题目三:LeetCode 474.一和零
本题中strs 数组里的元素就是物品,每个物品都是一个,而m 和 n相当于是一个背包,两个维度的背包。
- 确定dp数组及其下标的含义
 dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]。
- 确定递推公式
dp[i][j] = max(dp[i][j],dp[i-zeroNum][j-oneNum]+1)
- dp数组初始化
 因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。
- 确定遍历顺序
 01背包一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
for (string str : strs) { // 遍历物品
    int oneNum = 0, zeroNum = 0;
    for (char c : str) {
        if (c == '0') zeroNum++;
        else oneNum++;
    }
    for (int i = m; i >= zeroNum; i--) { // 遍历背包容量且从后向前遍历!
        for (int j = n; j >= oneNum; j--) {
            dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
        }
    }
}
- 举例推导dp数组
 strs = [“10”,“0001”,“111001”,“1”,“0”],m = 3,n = 3
  
 完整的代码实现如下:
class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0)); // 默认初始化0
        for (string str : strs) { // 遍历物品
            int oneNum = 0, zeroNum = 0;
            for (char c : str) {
                if (c == '0') zeroNum++;
                else oneNum++;
            }
            for (int i = m; i >= zeroNum; i--) { // 遍历背包容量且从后向前遍历!
                for (int j = n; j >= oneNum; j--) {
                    dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
                }
            }
        }
        return dp[m][n];
    }
};








![[附源码]Python计算机毕业设计SSM基于技术的高校学生勤工俭学管理系统的设计与开发(程序+LW)](https://img-blog.csdnimg.cn/6e24bfa958054206a2b7354ca2845d57.png)







![[附源码]JAVA毕业设计校园快递联盟系统(系统+LW)](https://img-blog.csdnimg.cn/ffc8d627721f48c99df4b53cde6432f4.png)


