自构物品的完全背包问题(完全平方数)

Posted C_YCBX Py_YYDS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自构物品的完全背包问题(完全平方数)相关的知识,希望对你有一定的参考价值。

题目

在这里插入图片描述

题目解析

首先声明这就是一个完全背包问题,为什么呢?因为题目就是需要你找到完全平方数去填补数字n使得填补所用的完全平方数最少,而这些完全平方数可以无限使用。显然我们不清楚的就是背包内要装的物品,因为题目并未给出。

关于背包内要装入的物品,我们根据题意可知是小于sqrt(n)的完全平方数,所以我们可以通过枚举1~sqrt(n)范围内的完全平方数得到背包内要装入的物品。

有这个物品后,我们就完全可以看作是零钱兑换

  • 给你不同的面额,要求用最少张的钞票兑换成金额n。

把题目转成了零钱兑换问题是不是有背包问题内味了?

接下来就是完全背包的讲解过程了。
dp关系不清楚可以看看我对昨天那道每日一题完全背包的讲解过程零钱兑换II
此题dp[i][j]代表选择前i类物品装满j所用的最少物品数。
d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j ] + d p [ i ] [ j − n u m s [ i − 1 ] ] ) dp[i][j]=min(dp[i-1][j]+dp[i][j-nums[i-1]]) dp[i][j]=min(dp[i1][j]+dp[i][jnums[i1]])

  • 有了基本的dp关系作背书,那么我们现在要思考就是如何设置base case来更新答案。由于需要更新的是最小值,我们需要把还未更新和非法的dp结果赋值为尽量大的值
  • 什么是非法的dp结果比如dp[0][34]什么物品都不选,怎么可能存在填满物品这件事?所以把它填为较大值作为min函数工具人。实际上初始值除了已经知晓dp结果的dp[..][0]=0,其余均初始化为较大值。
  • 最后既然已经知晓是完全背包问题,那么肯定可以压缩一维数组来遍历dp函数,这里的详情请看前面我挂的零钱兑换II的链接。

二维dp+自建物品

在这里插入图片描述

class Solution {
public:
    int numSquares(int n) {
//自己构造物品给背包
vector<int>nums;
for(int i=1;i<=sqrt(n);i++)nums.push_back(i*i);
    int size = nums.size();
    //由于是要根据dp关系求的最小值,所以应保证未更新的dp值够大,以用于更新最小值
    int dp[size+1][n+1];memset(dp,0x3f,sizeof(dp));
    //很明显base case是dp[..][0]无论前面的物品用与不用,构成容量为0的背包的所用个数只能是0
    //而dp[0][..]则明显是无法拼凑成任何数的,故只需要它为默认值就好
    for(int i=0;i<=size;i++)dp[i][0] = 0;
    //开始更新dp数组
    for(int i=1;i<=size;i++){
        for(int j=1;j<=n;j++){
            if(j>=nums[i-1])
            dp[i][j] = min(dp[i-1][j],dp[i][j-nums[i-1]]+1);
            else
            dp[i][j] = dp[i-1][j];
        }
    }
    return dp[size][n];
    }
};

一维dp+自建物品

在这里插入图片描述

class Solution {
public:
    int numSquares(int n) {
//自己构造物品给背包
vector<int>nums;
for(int i=1;i<=sqrt(n);i++)nums.push_back(i*i);
    int size = nums.size();
    //由于是要根据dp关系求的最小值,所以应保证未更新的dp值够大,以用于更新最小值
    int dp[n+1];memset(dp,0x3f,sizeof(dp));
   dp[0] = 0;
    //开始更新dp数组
    for(int i=1;i<=size;i++){
        for(int j=nums[i-1];j<=n;j++){
            dp[j] = min(dp[j],dp[j-nums[i-1]]+1);
        }
    }
    return dp[n];
    }
};

一维dp+非自建物品

在这里插入图片描述

class Solution {
public:
    int numSquares(int n) {
    //由于是要根据dp关系求的最小值,所以应保证未更新的dp值够大,以用于更新最小值
    int dp[n+1];memset(dp,0x3f,sizeof(dp));
   dp[0] = 0;
    //开始更新dp数组
    for(int i=1;i<=sqrt(n);i++){
        for(int j=i*i;j<=n;j++){
            dp[j] = min(dp[j],dp[j-i*i]+1);
        }
    }
    return dp[n];
    }
};

以上是关于自构物品的完全背包问题(完全平方数)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 279 完全平方数[动态规划] HERODING的LeetCode之路

leetcode 279. 完全平方数----完全背包的套路

完全背包——01背包方法数

完全背包问题-dp

完全背包问题

POJ 1252 Euro Efficiency ( 完全背包变形 && 物品重量为负 )