其他分享
首页 > 其他分享> > 背包问题1—01背包讲述

背包问题1—01背包讲述

作者:互联网

如果对与01背包有一些了解的可以不用看下面的讲述直接跳到代码 处行,看代码中穿插的例子即可理解01背包
问题描述:
有N件物品和一个容量为m的背包。第i件物品的费用是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
二维状态下的核心代码为
在写出核心代码之前,我先做一些代码中用到的基础的一些介绍:
装n个物品 ,毫无疑问每个物品都要进行尝试装入到背包中去,在对于这类题不熟悉的情况下,先用二维数组来解 【实际上用一位数组也就是一行代码的改变而已】我们首先定义一个二维数组dp[i][j]表示装到编号为i的物品【i前面的有一些物品可能没有被选中,因为主要目的是要达到最大价值】装进容量为j的背包中所能够取得的最大价值 ,至于让背包的容量从m【从最大容量开始是为了避免重复装进同一件物品】。
对于前面提到的重复讲解:当该遍历第i件物品的时候代码为
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);对于dp[i-1][j]表示装到i-1的物品占用了最大容量j所取得的最大价值 ,dp[i-1][j-w[i]]+v[i]是说如果装进第i个物品的那莫装进去了就要减去第i个物品所占据的空间,加上它所具有的价值也就是用了j的空间并且也加上第i件物品了;之后要做的就是把装与不装两个进行比较看哪个价值更大一些,把价值大的赋值给f[i][j];
我们是从最大容量开始算起的,加上第i个物品的话,第二层循环经过第一次让j=m(最大容量)计算后最大容量的价值已经确定,最大容量已经到了饱和状态也就是说装不下了,所以最大容量的价值判断就只有一次要么装要么不装;

for(i=1; i<=n; i++)/*遍历n个物品(每个物品都进行尝试
         看是否经过它进入背包后可以让背包达到最大的价值),*/
{
	for(j=m; j>=w[i]; j--)
	{//选择是否要装如第i件物品
		dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
	}
}

下面是一位数组的 代码

for(i=1; i<=n; i++)
/*下面就举一个例子来遍历一遍;
假设n为3最大容量m为10  
物品称号  该物品容量  价值
1           6         50
2           4         30
3           5         60
第一次放入1是dp[10]=dp[9]=dp[8]=dp[7]
=dp[6]=50(只要够6就可以装下第一组数据)
第二次放入2dp[10]由50变成了80因为dp[10-
    w[2]]+v[2]=dp[6]+v[2]=80,
比以前的dp[10]=50大,所以替换以前的数值。
数据的有变化是dp[10]=80,dp[5]=dp[4]=30;
第三次放入3dp[10]变成了90,因为
dp[10]=dp[10-w[3]]+v[3]=dp[5]+v[3]=30+60=90;
三次放入后最大的变为90了这样就算是找出最大的了;其他数组的变化自行推算*/
{
	for(j=m; j>=w[i]; j--)
	{
		dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
	}
}

下面我再给出01背包的完整模板代码,
题目来源:https://vjudge.net/contest/318227?tdsourcetag=s_pcqq_aiomsg#problem/I
模板代码:

#include<stdio.h>
int f[200050],v[200050],w[2000];
int main()
{
	int n,m,i,j;
	scanf("%d %d", &n,&m);
	for(i=1; i<=n; i++)
		scanf("%d %d", &w[i],&v[i]);
		for(i=1; i<=n; i++)
		{
				for(j=m; j>=w[i]; j--)
			{
				if(f[j]<f[j-w[i]]+v[i])
				f[j]=f[j-w[i]]+v[i];
			}
	}
	printf("%d", f[m]);
	return 0;
}

标签:背包,讲述,容量,件物品,代码,01,物品,dp
来源: https://blog.csdn.net/weixin_44606952/article/details/98944585