动态规划(3)

474

本地的dp数组由于需要考虑0和1两个元素,所以多了一维,是一个三维的dp数组,然后再使用滚动数组降至2维

递推公式:
dp[j][k]=max(dp[j][k],1+dp[j-num0][k-num1]);

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        //dp[i][j][k]代表有j个0和k个1时,最大子集的长度,取前i个
        int sz=strs.size();
        //vector<vector<vector<int>>> dp(sz,vector<vector<int>>(m+1,vector<int>(n+1,0)));
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));
        dp[0][0]=0;
        for(int i=0;i<sz;i++)
        {
            int num0=0;
            int num1=0;
            for(int j=0;j<strs[i].length();j++)
            {
                if(strs[i][j]=='0')
                {
                    num0++;
                }
                else
                {
                    num1++;
                }
            }
            for(int j=m;j>=num0;j--)
            {
                for(int k=n;k>=num1;k--)
                {
                    dp[j][k]=max(dp[j][k],1+dp[j-num0][k-num1]);
                }
            }
        }
        return dp[m][n];

    }
};

完全背包

与01背包的不同点是:

01背包是每个物品最多取一次
而完全背包不限制物品拿取的次数

所以就造成了遍历顺序的不同

01背包中为了每个物品只拿取一次,滚动数组的遍历是从大到小的

for(int i=0;i<n;i++)
    {
        for(int j=weight;j>=w[i];j--)
        {
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }

而完全背包为了物品被充分利用,要从小到大去便利

for(int i=0;i<n;i++)
    {
        for(int j=w[i];j<=weight;j++)
        {
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }

除此之外还有先遍历物品或是先遍历背包的区别:

在求装满背包有几种方案的时候,认清遍历顺序是非常关键的。

如果求组合数就是外层for循环遍历物品,内层for遍历背包。

如果求排列数就是外层for遍历背包,内层for循环遍历物品。

模板题

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int n,weight;
    cin>>n>>weight;
    vector<int> w(n);
    vector<int> v(n);
    for(int i=0;i<n;i++)
    {
        cin>>w[i]>>v[i];
    }
    vector<int> dp(weight+1,0);
    for(int i=0;i<n;i++)
    {
        for(int j=w[i];j<=weight;j++)
        {
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    cout<<dp[weight]<<endl;
    return 0;
}

518零钱兑换

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        //dp数组含义,组成amount有多少种组合
        vector<int> dp(amount+1,0);
        //dp初始化
        dp[0]=1;
        int n=coins.size();
        for(int i=0;i<n;i++)
        {
            for(int j=coins[i];j<=amount;j++)
            {
                dp[j]=dp[j]+dp[j-coins[i]];
            }
        }
        return dp[amount];
    }
};
posted @ 2024-01-18 10:33  LiviaYu  阅读(11)  评论(0)    收藏  举报