目录
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];
}
};
标签:遍历,背包,int,vector,物品,动态,规划,dp
From: https://www.cnblogs.com/liviayu/p/17971940