卡码网57.爬楼梯
思路:爬上n阶楼梯,每次最多可以上m个台阶 (1<=m<n)。确定dp数组及其下标的含义,dp[j]表示爬上j阶楼梯的方法数。递推公式dp[j] +=dp[j-i]; (1<=i<=m)。初始化dp数组,dp[0]=1,如果初始化dp[0]=0,后续dp的值都为0。遍历顺序,由于物品可以重复使用,因此遍历背包时正序。由于1阶+2阶与2阶+1阶是两种不同的方法,因此是排列问题,先遍历背包后遍历物品。打印dp数组,可以用于debug。
#include<iostream>
using namespace std;
#include<vector>
int method(int m,int n)
{
//定义dp数组及其下标含义 dp[j]表示爬到j层楼的楼顶需要的方法数
//递推公式 dp[j] += dp[j-i], 1<=i<=m。
//初始化 dp[0]=1。到达0阶的方法数
//遍历顺序 1阶+2阶 与 2阶+1阶 是两种不同的方法,因此这道题为排列问题
//循环顺序为先背包后物品
//打印dp数组,可以用于debug
vector<int> dp(n+1,0);
dp[0] =1;
for(int j = 1;j<=n;j++)
{
for(int i = 1;i<=m;i++)
{
if(j>=i)
{
dp[j]+=dp[j-i];
}
}
}
return dp[n];
}
int main()
{
int m;
int n ;
cin >>n;
cin>>m;
cout<< method(m,n);
system("pause");
return 0;
}
322.零钱兑换
思路:求可以凑成总金额的最小硬币个数,确定dp数组及其下标的含义,dp[j]表示凑成j金额的最小硬币数。递推公式 dp[j] = min( dp[j-coins[i]]+1, dp[j]).初始化dp数组,初始化dp数组为INT_MAX,因为如果能凑成金额j,dp数组值会被替换,如果不能凑成仍保持为INT_MAX. dp[0]=0;凑成0金额最小用0个硬币。遍历顺序,因为硬币可以重复使用,背包正序遍历,以为这道题求最小硬币个数因此,先遍历背包还是物品无所谓。打印dp数组,可以用于debug。
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
//coins面额从大到小往背包里放,贪心
//确定dp数组及其下标的含义,dp[j]代表 容量为j的背包可以放的最小个数
//递推公式 dp[j] = min(dp[j-coins[i]+1,dp[j]]);
//初始化dp数组 dp[0] = 0;
//确定递归顺序,可以重复放,从前往后循环
//这道题排列和组合都可以解决,因此先遍历背包还是物品都可以
//打印dp数组,可以用于debug
vector<int> dp(amount+1,INT_MAX);
dp[0] =0;
for(int j = 1;j<=amount;j++)
{
for(int i = 0;i<coins.size();i++)
{
if(j>=coins[i]&&dp[j-coins[i]]!=INT_MAX)
{
dp[j] = min(dp[j-coins[i]]+1,dp[j]);
}
}
}
return (dp[amount]==INT_MAX)?-1:dp[amount];
}
};
279.完全平方数
思路:给定一个整数n,返回和为n的最小平方和个数。确定dp数组及其下标含义,dp[j]表示凑满j的最小平方和个数。递推公式dp[j] = min(dp[j-i*i]+1,dp[j])。初始化dp为INT_MAX,dp[0]为0。遍历顺序,因为平方和可以重复利用,遍历背包正序,这道题考虑组合还是排列不会影响结果,因此先遍历背包还是物品都可以。打印dp数组,可以用于debug。
class Solution {
public:
int numSquares(int n) {
//确定dp数组及其下标的含义 dp[j]为 装满背包容量为j的最小数量
//递推公式 dp[j] = min(dp[j-i^2]+1,dp[j]);
//初始化dp数组 dp[0]=0;
//遍历顺序 物品可以重复,因此遍历背包是正序
//打印dp数组,可以用于debug
vector<int> dp(n+1,INT_MAX);
dp[0]=0;
for(int i = 1;i*i<=n;i++)
{
for(int j = i*i;j<=n;j++)
{
dp[j] = min(dp[j-i*i]+1,dp[j]);
}
}
return dp[n];
}
};
收获
熟练使用dp数组,理解dp数组的含义,以及问题对递推公示的影响,物品是否重复判断问题是01背包问题还是完全背包问题,遍历背包是倒序还是正序,判断问题是组合还是排列,组合问题先遍历物品,排列问题先遍历背包,如果组合和排列不对结果产生影响,先遍历哪个都可以。