01背包问题及变体
创始人
2025-05-31 07:31:58

这几天做面试题,背包问题是一个常考的考点,我没有复习到位,都很难做出来。

很久以前我看到01背包问题的最基础那里,看完,这么简单,我会背包问题了。。。结果这几次面试题都不带重样的背包,不禁让我回来继续整理总结。非常抱歉,以下代码是我在不同时期写得,所以代码有一些是C++的有一些是java的。


1.01背包基础

https://www.acwing.com/problem/content/description/2/

这就是典型的01背包,非常简单,了解了状态定义就会写

dp[i][j]表示当容量为j的时候前i个物品的最大价值是什么?

对于初学者,建议先画表格。画了一个表格什么都明白了。

看是没有用滴,自己推理一边就知道状态方程怎么来的了。

推理方程:

dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i])

含义:不要当前的i,要当前的i。如果要当前的i的话,要看装不装的下,怎么叫装得下?j >= w[i]叫装得下.有这个思路就可以写最普通的代码了。

#include
using namespace std;
#define N 1001
int v[N];
int w[N];
int f[N][N];
int main()
{int n,m;cin >> n >> m;for(int i = 1;i <= n;i++){cin >> v[i] >> w[i];}for(int i = 1;i <= n;i++){for(int j = 0;j <= m;j++){f[i][j] = f[i - 1][j];if(v[i] <= j) f[i][j] = max(f[i][j],f[i - 1][j - v[i]] + w[i]);}}cout << f[n][m];return 0;
}

这是最常规的,那么实际上每次更新i的过程中,只用到了i - 1的状态,可以改成一维数组优化。

#include
using namespace std;
int main()
{int n, v;cin >> n >> v;int cap[n + 1] = {0};int val[n + 1]= {0};for(int i = 1; i <= n; i++) {cin >> cap[i] >> val[i];}int dp[v + 1] = {0};for(int i = 1; i <= n; i++) {for(int j = 1; j <= v; j++) {if(j - cap[i] >= 0)dp[j] = max(dp[j], dp[j - cap[i]] + val[i]);}}cout << dp[v] << endl;return 0;
}

上面的代码提供了错误的示范,j = 1, j <= v; j++,思路是没错,但是滚动的过程中,会刷新dp[j],所以一定要从后往前滚动才可以。

#include
using namespace std;
int main()
{int n, v;cin >> n >> v;int cap[n + 1] = {0};int val[n + 1]= {0};for(int i = 1; i <= n; i++) {cin >> cap[i] >> val[i];}int dp[v + 1] = {0};for(int i = 1; i <= n; i++) {for(int j = v; j >=0; j--) {if(j - cap[i] >= 0)dp[j] = max(dp[j], dp[j - cap[i]] + val[i]);}}cout << dp[v] << endl;return 0;
}

上面的代码依然可以继续优化,如果j >= cap[i]表示买得起当前物品,否则表示买不起。买不起就不用动了,可以直接写成

for(int j = v; j >= cap[i]; j--)dp[j] = max(dp[j], dp[j - cap[i] + val[i]);

01背包的变体例题

https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4?tpId=37&tqId=21239&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D37&difficulty=undefined&judgeStatus=undefined&tags=&title=

对于上面的01背包基础还是要多多去反复品味一下,非常之妙啊,他变个形状可能就不认识了,但是一想还是01背包。

本题可以先处理一下,将每一种主键作为背包的元素,附件作为主键的状态。

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int money = sc.nextInt() / 10;int m = sc.nextInt();int[][] w = new int[m + 1][3];int[][] v = new int[m + 1][3];int id = 1;int[][] pre = new int[m][3];Map map = new HashMap<>();for(int i = 0; i < m; i++) {int price = sc.nextInt() / 10;int imp = sc.nextInt();int states = sc.nextInt();pre[i][0] = price;pre[i][1] = imp;pre[i][2] = states;if(states == 0) {w[id][0] = price;v[id][0] = price * imp;map.put(i, id);id++;}}for(int i = 0; i < m; i++) {int states = pre[i][2];if(states == 0)continue;int price = pre[i][0];int imp = pre[i][1];int idx = map.get(states - 1);if(w[idx][1] == 0) {w[idx][1] = price;v[idx][1] = imp * price;} else {w[idx][2] = price;v[idx][2] = imp * price;}}int[] dp = new int[money + 1];for(int i = 1; i <= id; i++) {for(int j = money; j >= 1; j--) {int t = dp[j]; //不买if(j >= w[i][0]) t = Math.max(t, dp[j - w[i][0]] + v[i][0]); //买主if(j >= w[i][0] + w[i][1]) t = Math.max(t, dp[j - w[i][0] - w[i][1]] + v[i][0] + v[i][1]); //主1if(j >= w[i][0] + w[i][2]) t = Math.max(t, dp[j - w[i][0] - w[i][2]] + v[i][0] + v[i][2]); //主2if(j >= w[i][0] + w[i][1] + w[i][2]) t = Math.max(t, dp[j - w[i][0] - w[i][1] - w[i][2]] + v[i][0] + v[i][1] + v[i][2]);dp[j] = t;}}System.out.println(dp[money] * 10);}
}

完全背包问题

https://oj.youdao.com/problem/725

如题所示,完全背包问题和01背包问题的差别在于:完全背包问题是可以重复出现多次的。

#include
using namespace std;
int main()
{int m, n;cin >> m >> n;int w[n + 1] = {0};int v[n + 1] = {0};int dp[m + 1] = {0};for(int i = 1; i <= n; i++) {cin >> w[i] >> v[i];}for(int i = 1; i <= n; i++) {for(int j = w[i]; j <= m; j++) {dp[j] = max(dp[j], dp[j - w[i]] + v[i]);}}cout << "max=" << dp[m] << endl;return 0;
}

如果熟悉了上面的01背包,再看这个应该很简单,如果买不起当前的,很显然就不买。

否则dp[j - w[i]]+ v[i]


https://leetcode.cn/problems/coin-change-ii/

这也是个完全背包问题。。。如果不告诉我,我真的联想不到,可能脑子不好使吧。

class Solution {
public:int change(int amount, vector& coins) {vector dp(amount + 1);dp[0] = 1;for(int t: coins) {for(int i = t; i <= amount; i++) {dp[i] += dp[i - t];}}return dp[amount];}
};

https://leetcode.cn/problems/coin-change/

零钱兑换问题1,也可以看作是一个完全背包问题。

int coinChange(vector& coins, int amount) {vector dp(amount + 1, 10000000);dp[0] = 0;for(int coin: coins) {if(coin > amount) continue;dp[coin] = 1;for(int j = coin + 1; j <= amount; j++) {dp[j] = min(dp[j - coin] + 1, dp[j]);}print(dp);}return dp[amount] == 10000000 ? -1 : dp[amount];}
int print(vector &dp) {for(int d: dp)cout << d << " ";cout << endl;return 0;}

这里我打印了一个case看看


0 1 2 3 4 5 6 7 8 9 10 11 
0 1 1 2 2 3 3 4 4 5 5 6 
0 1 1 2 2 1 2 2 3 3 2 3 

https://leetcode.cn/problems/combination-sum-iv/

组合总和问题:这里又变了一下,我又没想到。。。

class Solution {
public:int combinationSum4(vector& nums, int target) {vector dp(target + 1);dp[0] = 1;for(int i = 1; i <= target; i++) {for(int n: nums) {if(i >= n && dp[i] < INT_MAX - dp[i - n]) dp[i] += dp[i - n];}}return dp[target];}
};

相关内容

热门资讯

这是“外国入侵”!特朗普发声;... 编辑 | 七三 美股齐涨周二,美股连续第三日上涨,标普500指数创下至少三个月来新高。特斯拉领涨推...
暴涨后暴跌!币圈盯上Labub... 在全球爆火的Labubu,最近被币圈盯上了。 记者注意到,随着泡泡玛特旗下潮玩IP(知识产权)Lab...
【环球财经】英国零售商5月销售... 转自:新华财经 新华财经北京6月10日电(王姝睿) 周二公布的对英国零售商和消费者的调查显示,由于家...
君禾股份:“十城领航”战略成功... 在五金机电行业的激烈竞争中,君禾股份(603617.SH)正以其独特的战略布局和稳健的发展步伐,逐渐...
格力电器业绩会: 多个板块具备... 证券时报记者 李映泉“格力电器是多元化科技型工业集团,其中工业制品、高端装备、精密模具、电子元器件、...
美银证券报告:制造业“回流美国... 来源:环球时报【环球时报特约记者 甄翔】为推行“制造业回流”政策,美国政府祭出关税手段以鼓励企业将生...
工业富联目标涨幅近40%,莱特... 6月10日,券商给予上市公司目标价共10次,按最新收盘价计算,目标价涨幅排名居前的公司有工业富联、孩...
申万宏源2025资本市场夏季策... 证券时报记者 孙翔峰6月10日,申万宏源2025资本市场夏季策略会在北京举行。会上,申万宏源首席经济...
比亚迪、赛力斯等多家车企承诺支... 昨日A股6月10日,A股三大指数午后集体走低,截至收盘,沪指跌0.44%,深成指跌0.86%,创业板...
喜马拉雅200亿栖身腾讯音乐,... 12.6亿美元现金,加上5.5%的股权,这是腾讯音乐给出的对价,移动互联网最后一颗遗珠——喜马拉雅,...
重大资产重组!4000亿算力航... 作 者丨雷晨编 辑丨朱益民 江佩佩停牌10个交易日后,海光信息(688041.SH)换股吸收合并中科...
原创 一... 近日,美的在海外市场召回170万台空调引发关注。 据多家美国媒体报道,6月5日,美的宣布召回在美国和...
环球时报社评:这篇对任正非的专... 6月10日,《人民日报》头版刊发了对华为首席执行官任正非的专访。在谈到面对外部封锁打压时,任正非表示...
如何走好人生下坡路? 走好人生下坡路,首先要摒弃那些让自己沉迷和堕落的事物。比如过度的娱乐、消极的情绪,它们会像藤蔓一样逐...
刘楚昕 请你提供一些关于刘楚昕的具体信息呀,比如她的职业、性格特点、主要事迹等,这样我才能更准确地为你写 2...
牛市早报|多家车企承诺支付账期... 【市场数据】6月10日收盘,上证综指跌0.44%,报3384.82点;科创50指数跌1.47%,报9...
星巴克突然宣布大降价,数十款产... 最近几年,只要说起咖啡茶饮产业的价格战,相信大多数人都不会陌生,无论是瑞幸、库迪还是蜜雪冰城、茶百道...
房地产崩盘后,瓷砖巨头血亏5.... 早年间,房地产行业的蓬勃发展推动了建筑墙、地瓷砖市场的巨大需求,尤其是广东瓷砖,在国内市场占有重要地...
华泰证券:运动相机和全景相机行... 华泰证券研报表示,随着户外运动的兴起、社交媒体内容的超速增长以及VR/AR的逐步成熟,运动相机和全景...
“第二稀土”,一片繁荣 “第二稀土”,那是一片充满蓬勃生机的繁荣景象。在这里,各种珍稀资源如璀璨星辰般汇聚,每一处角落都散发...
爆火的养生水,还得长期“煎熬”... 斑马消费 陈晓京比起冰美式单纯的提神功效,中式养生水更懂得如何撩动年轻人的心。毕竟,包装上醒目的配料...
宠物行业发展动能强劲,板块投资... 今年以来,宠物经济发展势头迅猛,宠物已逐渐成为情感寄托和家庭的重要成员,宠物消费市场规模持续扩大。W...
缩短发售时间,抢先入市!创新药... 估值拉升过快的背景下,多只医药主题基金宣布提前结募。在新基金发行市场由重首发规模变为重首发体验的新理...
王石最新发声!万科晚间突发公告... 据澎湃新闻,6月10日,第十八届全球光伏&储能大会暨展览会开幕式于上海国家会展中心举办。深石集团、万...
暴涨后暴跌!币圈盯上Labub... 在全球爆火的Labubu,最近被币圈盯上了。记者注意到,随着泡泡玛特旗下潮玩IP(知识产权)Labu...
特斯拉突然大涨!美股创阶段新高... 2025.06.11本文字数:866,阅读时长大约1.5分钟作者 |第一财经 胡弋杰周二,美股连续第...
定制芯片助推博通股价飙升70%... 近期,博通股价在两个月内上涨超过70%,市值一度突破1万亿美元,跻身美股市值前列。这波涨势主要得益于...
方正科技拟定增募资不超过19.... 【大河财立方消息】6月10日,方正科技集团股份有限公司(简称方正科技)公告称,公司拟向包括控股股东珠...
港股IPO市场火热,A+H上市... 今年以来,港股IPO市场持续活跃,募资金额已超780亿港元,同比增长超670%。宁德时代、恒瑞医药等...
一边离谱宣传一边大规模召回,美... 近日,美的在海外市场召回170万台空调引发关注。据多家美国媒体报道,6月5日,美的宣布召回在美国和加...