LeetCode 494目标和 474一和零 卡码网52(完全背包)携带研究材料 LeetCode 518零钱兑换-ii 377组合总和-iv | 代码随想录25期训练营day43/44

动态规划算法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];
}

猜你喜欢

转载自blog.csdn.net/weixin_66706867/article/details/134864586