目录
前言:
一,完全背包问题
问题描述:
模板题目:
题目解析:
代码:
空间优化:
二,典例
1,零钱兑换
题目解析:
算法分析:
代码:
空间优化:
2,零钱兑换2
题目解析:
算法分析:
代码:
空间优化:
3,完全平方数
题目解析:
算法解析:
代码:
空间优化:
前言:
上篇:01背包CSDN
一,完全背包问题
问题描述:
有n个物品,和一个容量为V的背包,每种物品都可以无限使用。每个物品都有两个属性,体积v和价值w。求解:将那些物品放入背包,可使这些物品的总体积不超过背包的容量,且总价值最大,输出最大价值。
与01背包问题不同的是,完全背包的物品是可以无限选取的,而01背包的物品只会面临选或者不选。
模板题目:
题目链接:【模板】完全背包_牛客题霸_牛客网
题目解析:
与01背包问题相似,我们定义出状态表示:dp[i][j]表示,在前i个物品中选,总体积不超过j情况下,所能装的最大价值。
对于第二问,状态表示为: dp[i][j]表示,在前i个物品中选,总体积正好等于j的情况下,所能装的最大价值。
代码:
#include <iostream>
using namespace std;
#include <string.h>const int N=1010;
int n,V,v[N],w[N];
int dp[N][N];
int main()
{cin>>n>>V;for(int i=1;i<=n;i++){cin>>v[i]>>w[i];}for(int i=1;i<=n;i++)for(int j=0;j<=V;j++){dp[i][j]=dp[i-1][j];if(j>=v[i])dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);}cout<<dp[n][V]<<endl;memset(dp,0,sizeof(dp));for(int j=1;j<=V;j++)dp[0][j]=-1;for(int i=1;i<=n;i++)for(int j=0;j<=V;j++){dp[i][j]=dp[i-1][j];if(j>=v[i]&&dp[i][j-v[i]]!=-1)dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);}cout<<(dp[n][V]==-1?0:dp[n][V])<<endl;return 0;
}
空间优化:
利用滚动数组做空间上的优化,与01背包的原理相似
#include <iostream>
using namespace std;
#include <string.h>const int N=1010;
int n,V,v[N],w[N];
int dp[N];
int main()
{cin>>n>>V;for(int i=1;i<=n;i++){cin>>v[i]>>w[i];}for(int i=1;i<=n;i++)for(int j=v[i];j<=V;j++){dp[j]=max(dp[j],dp[j-v[i]]+w[i]);}cout<<dp[V]<<endl;memset(dp,0,sizeof(dp));for(int j=1;j<=V;j++)dp[j]=-1;for(int i=1;i<=n;i++)for(int j=v[i];j<=V;j++){if(dp[j-v[i]]!=-1)dp[j]=max(dp[j],dp[j-v[i]]+w[i]);}cout<<(dp[V]==-1?0:dp[V])<<endl;return 0;
}
二,典例
1,零钱兑换
本题链接:LCR 103. 零钱兑换 - 力扣(LeetCode)
题目解析:
coins数组中不同面值的硬币,可以看成是n个物品。从coins数组中挑选硬币,使其总和等于amount的最少硬币数。其中,每种硬币是可以无线选取的。可以用完全背包的思路解题。
算法分析:
代码:
class Solution {
public:int coinChange(vector<int>& coins, int amount) {int n=coins.size();const int INF=0x3f3f3f3f;vector<vector<int>> dp(n+1,vector<int>(amount+1));for(int j=1;j<=amount;j++)dp[0][j]=INF;for(int i=1;i<=n;i++)for(int j=0;j<=amount;j++){dp[i][j]=dp[i-1][j];if(j>=coins[i-1])dp[i][j]=min(dp[i][j],dp[i][j-coins[i-1]]+1);}return dp[n][amount]>=INF?-1:dp[n][amount];}
};
空间优化:
class Solution {
public:int coinChange(vector<int>& coins, int amount) {int n=coins.size();const int INF=0x3f3f3f3f;vector<int> dp(amount+1);for(int j=1;j<=amount;j++)dp[j]=INF;for(int i=1;i<=n;i++)for(int j=coins[i-1];j<=amount;j++){dp[j]=min(dp[j],dp[j-coins[i-1]]+1);}return dp[amount]>=INF?-1:dp[amount];}
};
2,零钱兑换2
本题链接:518. 零钱兑换 II - 力扣(LeetCode)
题目解析:
本题求的是不同的组合数,上题是求最少硬币数。
算法分析:
代码:
class Solution {
public:int change(int amount, vector<int>& coins) {int n = coins.size();//数据相加后 可能会超出范围vector<vector<double>> dp(n + 1, vector<double>(amount + 1, 0));dp[0][0] = 1;for (int i = 1; i <= n; i++)for (int j = 0; j <= amount; j++) {dp[i][j] = dp[i - 1][j];if (j >= coins[i - 1])dp[i][j] += dp[i][j - coins[i - 1]];}return dp[n][amount];}
};
空间优化:
class Solution {
public:int change(int amount, vector<int>& coins) {int n = coins.size();vector<double> dp(amount + 1);dp[0] = 1;for (int i = 0; i < n; i++)for (int j = coins[i]; j <= amount; j++)dp[j] += dp[j - coins[i]];return dp[amount];}
};
3,完全平方数
本题链接:279. 完全平方数 - 力扣(LeetCode)
题目解析:
一个整数n拆成几个完全平方数的和,求完全平方数的最少数量。
算法解析:
对于一个整数n,我们在找它的完全平方数和时,只会在1到根号n之前找。比如中13的完全平方数,我们会找4和9,即2的平方和3的平方。
代码:
class Solution {
public:int numSquares(int n) {int m=sqrt(n);vector<vector<int>> dp(m+1,vector<int>(n+1));for(int j=1;j<=n;j++)dp[0][j]=0x3f3f3f3f;for(int i=1;i<=m;i++)for(int j=0;j<=n;j++){dp[i][j]=dp[i-1][j];if(j>=i*i)dp[i][j]=min(dp[i][j],dp[i][j-i*i]+1);}return dp[m][n];}
};
空间优化:
class Solution {
public:int numSquares(int n) {int m=sqrt(n);vector<int> dp(n+1);for(int j=1;j<=n;j++)dp[j]=0x3f3f3f3f;for(int i=1;i<=m;i++)for(int j=i*i;j<=n;j++){dp[j]=min(dp[j],dp[j-i*i]+1);}return dp[n];}
};