动态规划算法5
LeetCode 494 目标和 2023.12.7
int findTargetSumWays(vector<int>& nums, int target) {
//该题中,分为两个子数组,left、right,对其中值没作处理;有两种符合+-,
//+left-right=target,left+right=sum;推出 left=(target+sum)/2
//所以求解数组中子数组和满足left的种数即可
//sum存储数组和
int sum = accumulate(nums.begin(), nums.end(), 0);
//两种情况直接返回0:target绝对值大于sum;bag为小数时
if(abs(target) > sum || ((sum + target) % 2) == 1)
return 0;
//要求背包容量为bag时装满bag的种数
int bag = (sum + target) / 2;
//1确定dp数组,其下标含义为装满j容量的种数
vector<int> dp(bag+1, 0);
//3初始化,dp[j] += dp[j - nums[i]],dp[0]=1,这里不能初始化为0,否则解永远为0
dp[0] = 1;
//2确定递推公式 4确定遍历顺序
for (int i = 0; i < nums.size(); i++)
{
//避免重复计算,采样倒序遍历
for (int j = bag; j >= nums[i]; j--)
{
//这里递推公式保证了背包始终都装满的条件
dp[j] = dp[j] + dp[j - nums[i]];
}
}
return dp[bag];
}
LeetCode 474 一和零 2023.12.7
int findMaxForm(vector<string>& strs, int m, int n) {
//此题背包为要求量有两个,0的个数和1的个数
//1确定dp数组,其下标含义为有i个0,j个1的字符串的个数,最后答案为dp[m][n]
//3初始化,dp[0][0]等于0,其他值也为0
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
//2确定递推公式,4确定倒序遍历顺序
for(string str : strs)
{
//计算该字符串中0和1的个数
int x = count(str.begin(), str.end(), '0');
int y = count(str.begin(), str.end(), '1');
//二维倒序遍历,保证每个字符串只使用一次,0和1的遍历顺序可互换
for (int i = m; i >= x; i--)
{
for (int j = n; j >= y; j--)
{
//i个0,j个1的字符串个数=max(遍历前面字符串i个0,j个1的字符串个数,i-x个0j-y个1的字符串个数+1(当前字符串))
dp[i][j] = max(dp[i][j], dp[i-x][j-y] + 1);
}
}
}
return dp[m][n];
}
卡码网 52 (完全背包)携带研究材料 2023.12.6
#include<bits/stdc++.h>
using namespace std;
int main()
{
//材料种类及背包大小
int num, bagsize;
cin >> num >> bagsize;
//每种材料的空间及价值
vector<int> room(num, 0);
vector<int> value(num, 0);
for(int i = 0; i < num; i++)
cin >> room[i] >> value[i];
//1确定dp数组,其下标表示容量为j的背包最大可装价值
//3初始化全部为0
vector<int> dp(bagsize+1, 0);
//2确定递推公式 4确定递推顺序
for(int i = 0; i < num; i++)
{
//完全背包和01背包的区别:完全背包每个物品能放无限次,01背包最多只能放1次
//因为完全背包可以放无限次,所以背包容量正序遍历,从room[i]到bagsize
for(int j = room[i]; j <= bagsize; j++)
dp[j] = max(dp[j], dp[j-room[i]]+value[i]);
}
cout << dp[bagsize] << endl;
return 0;
}
LeetCode 518 零钱兑换-ii 2023.12.7
int change(int amount, vector<int>& coins) {
//1确定dp数组,其下标表示凑成j元的种数
vector<int> dp(amount+1, 0);
//3初始化,dp[0]需要为1,否则dp数组都为0,这里求的是种数
dp[0] = 1;
//2确定递推公式,4确定遍历顺序
for (int i = 0; i < coins.size(); i++)
{
//因为为完全背包,所以顺序遍历
for (int j = coins[i]; j <= amount; j++)
//满足j元的种数=之前遍历的满足j元的种数+满足j-coins[i]元的种数(与nums[i]元凑成j元)
dp[j] += dp[j-coins[i]];
}
return dp[amount];
}
LeetCode 377 组合总和-iv 2023.12.7
int combinationSum4(vector<int>& nums, int target) {
//1确定dp数组,其下标表示凑成i值的排列数
vector<int> dp(target+1, 0);
//3初始化,dp[0]需要为1,否则dp数组都为0,这里求的是种数
dp[0] = 1;
//2确定递推公式,4确定遍历顺序
//如果求组合数就是外层for循环遍历物品,内层for遍历背包。
//如果求排列数就是外层for遍历背包,内层for循环遍历物品。
for (int i = 0; i <= target; i++)
{
//因为为完全背包,所以顺序遍历
for (int j = 0; j < nums.size(); j++)
{
//满足i值的排列数=之前遍历的满足i值的排列数+满足i-nums[j]的种数(与nums[j]凑成i值)
//要满足背包空间值>=当前遍历值nums[j],后面这个是为了应对奇葩样例
if(i >= nums[j] && dp[i] < INT_MAX - dp[i - nums[j]])
dp[i] += dp[i-nums[j]];
}
}
return dp[target];
}