首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【背包问题】完全背包

【背包问题】完全背包

作者头像
用户11719958
发布2025-12-30 14:27:56
发布2025-12-30 14:27:56
1160
举报

前言:

上篇:01背包CSDN

一,完全背包问题

问题描述:

有n个物品,和一个容量为V的背包,每种物品都可以无限使用。每个物品都有两个属性,体积v和价值w。求解:将那些物品放入背包,可使这些物品的总体积不超过背包的容量,且总价值最大,输出最大价值。

与01背包问题不同的是,完全背包的物品是可以无限选取的,而01背包的物品只会面临选或者不选。

模板题目:

题目链接:【模板】完全背包_牛客题霸_牛客网

题目解析:

与01背包问题相似,我们定义出状态表示:dp[i][j]表示,在前i个物品中选,总体积不超过j情况下,所能装的最大价值。

对于第二问,状态表示为: dp[i][j]表示,在前i个物品中选,总体积正好等于j的情况下,所能装的最大价值。

代码:
代码语言:javascript
复制
#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背包的原理相似

代码语言:javascript
复制
#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的最少硬币数。其中,每种硬币是可以无线选取的。可以用完全背包的思路解题。

算法分析:
代码:
代码语言:javascript
复制
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];
    }
};
空间优化:
代码语言:javascript
复制
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)

题目解析:

本题求的是不同的组合数,上题是求最少硬币数。

算法分析:
代码:
代码语言:javascript
复制
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];
    }
};
空间优化:
代码语言:javascript
复制
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的平方。

代码:
代码语言:javascript
复制
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];
    }
};
空间优化:
代码语言:javascript
复制
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];
    }
};
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 一,完全背包问题
    • 问题描述:
    • 模板题目:
    • 题目解析:
    • 代码:
    • 空间优化:
  • 二,典例
    • 1,零钱兑换
    • 2,零钱兑换2
    • 3,完全平方数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档