01背包问题(1)

本文详细解析了01背包问题的解决方法,包括问题描述、输入输出格式、问题分析及算法实现过程。通过实例讲解了如何使用动态规划算法求解背包问题,实现物品价值最大化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 题目

(此题来源于郭炜《算法基础与在线实践》,结合教材和自己体会所写)

1.1 问题表述

有n种物品和容量为m的背包,每个物品可以选择放或者不放在背包里面(物品最多可以被选择一次),每个物品的体积为wi和价值为di,问背包价值最大为多少。

通俗来讲,假设小黑去超市购物,购物车大小一定,每个商品的价值和大小都不一样,问怎样装购物车装满的情况下物品总价值最大。01背包问题就是每种物品至多拿一个,而完全背包问题是每种物品可以拿多个。

1.2 输入数据

第一行为整数N(物品种类)和M(背包容量)。从第二行到最后一行每行有两个整数,分别代表物品的体积wi和价值di。

1.3 输入

4 6

1 4

2 6

3 12

2 7

1.4 输出

23

2 问题分析

此题共有n中物品,每种物品可以选择放或者不放在背包里面,穷举所有可能,一共有2的n次方种方法,显然时间复杂度过高,n只要稍微大一些,就会超时。

所以要选用其他方法。对于该问题,对于所有物品,至少要遍历一遍,来决定其放或者不放,所以物品的种类就是外层循环。当遍历到第i种物品时,有两种状态,放或者不放,用F[i]表示放到第i种物品的价值,F[i] = max(放第i种物品,不放第i种物品),当放第i种物品时,也就意味着背包的剩余容积会变小,相应的总价值会增加。

上面所述,把物品的种类当作第一层循环,则可以把背包的容积当作第二层循环。对于第二层循环,可以想象当背包容量为0时、为1时、为k时、直至为m时,而以此为角标对数组进行取值,F[k]就是背包容量为k时的价值。也就是说用物品种类作为第一层循环,和背包容量作为第二层循环遍历了所有可能,然后进行实时更新覆盖掉次优解。

3 代码编写

#include <iostream>
#include <algorithm>
using namespace std;

struct Good {    //物品结构体,包含物品体积和价值两个属性
	int w;      //体积
	int d;      //价值
};

void test() {
	int N, M;
	cin >> N >> M;			      //N代表物品的种类,M代表背包的容积
	Good* Goods = new Good[N + 1];        //物品数组
	int* F = new int[M + 1];	      //背包容积数组
	for (int i = 1; i <= N; i++) {        //为了方便计数,角标以1开始
		cin >> Goods[i].w >> Goods[i].d;  //初始化物品数组
	}
	for (int i = 0; i <= M; i++) {        //初始化背包容积的价值数组
		F[i] = 0;
	}

	//开始写两层循环,外层循环用物品种类,内层循环用背包容积,遍历物品种类所有可能和背包容积的所有可能
	for (int i = 1; i <= N; i++) {        //从第1个物品开始遍历
		for (int j = M; j >= 0; j--) {    //背包容积遍历
			if (Goods[i].w <= j) {        //如果第i种物品的体积小于容积为j时背包的容量,则表示该物品可以被放进去
				F[j] = max(F[j], F[j - Goods[i].w] + Goods[i].d);
				//F[j]表示不放第i种物品,容积不变,价值不变
				//F[j-Goods[i].w]+Goods[i].d表示放第i种物品,容积变小,价值变大
			}
		}
	}
	cout << F[M] << endl;
}

int main() {
	test();
	return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值