01背包问题详解+测试数据

本文介绍了如何使用动态规划和递归策略解决经典的01背包问题。给出了C语言实现的二维数组和递归两种方法。动态规划方案通过创建二维数组B来存储每个物品和背包容量下的最大价值。递归方法则从最后一个商品开始,判断是否放入背包,根据当前商品重量和背包容量决定价值最大化。对于大规模数据,递归方法可能效率较低。测试数据展示了不同商品和背包容量下的价值计算过程。
摘要由CSDN通过智能技术生成

题目

有N件物品和一个容量为V的背包。第i件物品的重量是c[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大。

0 1即简单的 要 /不要 这个商品

公式:k代表第几个商品 c代表背包剩余承重
在这里插入图片描述

解释:
1.如果第k件太重,那就不装他,价值还是上一件的价值
2.如果没有超重,那就比较:(1)要这件商品(上一次没有要这件商品且背包剩余承重正好等于这第k件商品的重量时的价值加上第k件的价值)(2)不要这件商品(价值还是上一件的价值)

现在有5个商品,背包容量为6

序号商品大小商品价值
012
124
234
345
456

输入

5 6             
1 2
2 4
3 4
4 5 
5 6

输出

10

用二维数组

在这里插入图片描述

套公式+看注释

#include<stdio.h>
#include<stdlib.h>
int n,V;		//n代表n件商品 V代表背包承重 
double **B;		
int *w;			//每个物品重量
double *v;		//每个物品价值
void Knapsack()
{
	//创建数据 
	scanf("%d%d",&n,&V);
	int i,j;
	B=(double **)malloc((n+1)*sizeof(double*));
	for(i=0;i<(n+1);i++)
	{
		B[i]=(double *)malloc((V+1)*sizeof(double));
	}
	for(i=0;i<=n;i++)
	{
		for(j=0;j<=V;j++)
		{
			B[i][j]=0;
		}
	}
	w=(int*)malloc((n+1)*sizeof(int ));
	v=(double*)malloc((n+1)*sizeof(double ));
	for(i=1;i<=n;i++)
	{
		scanf("%d%lf",&w[i],&v[i]);
	}
	//结束创建
	//核心代码//公式 
	int k,c;
	for(k=1;k<=n;k++)
	{//k代表第几个商品 c代表背包剩余承重 
	 //以背包为内循环,一件商品一件商品往下填价值
		for(c=1;c<=V;c++)
		{
			if(w[k]>c)
				B[k][c]=B[k-1][c];
			else
			{					// ↓既然背包容量已经够了 那就用当没有要他时背包里之前的容量正好差一个他的体积时的价值加上他的价值 
				double value_1 = B[k-1][c-w[k]]+v[k];		//要 
				double value_2 = B[k-1][c];					//不要
								// ↑上一次背包这样容量的价值 
				if(value_1>value_2)
					B[k][c]=value_1;
				else B[k][c]=value_2;
			}
		}
	}
}
int main()
{
	Knapsack();
	printf("%.0lf",B[n][V]);
	return 0;
}

函数递归

要4
不要4
要3
不要3
要2
不要2
要1
不要1
要0
不要0
要不起321,要0
不要0
要不起2要1
要不起2不要1
要0
不要0
要1
不要1
不要0
要0
不要0
不要0
不要0
不要0
B <4 ,6>
B <3, 1>+v<4> =6
B<3,6> =0
B<2,2>+v<3> =5
B<2,6> =0
B<1,3>+v<2> =4
B<1,6> =0
B<0,4>+v<1> =4
B<0,6> =0
B<-1,5>+v<0> =2
B<-1,6> =0
B<-1,0>+v<0> =8
B<-1,1> =6
B<0,0>+v<1> =9
B<0,2> =5
B<-1,1>+v<0> =7
B<-1,2> =5
B<0,1>+v<1> =8
B<0,3> =4
B<-1,3> =4
B<-1,2>+v<0> =6
B<-1,1> =8
B<-1,0> =10
B<-1,4> =4
B<-1,3> +v<0>=6

从最下面一个商品开始递归
每层递归判断
1.限制1:商品是否访问完 完了则return 0;
2.限制2:判断是否大小超过背包剩余大小,超过了则判断下一个商品
3.如果都没有限制住,则进入上面一个商品的判断,并判断要这个商品与不要这个商品价值的大小

源码:

#include<stdio.h>
double B(int k,int c);		//k代表第几件,W代表背包容量还剩多少 B代表价钱 
double list[1010][2];
int main()
{
	int n,V; //n件商品 V为背包容量 
	scanf("%d%d",&n,&V);
	int i,j;
	for(i=0;i<n;i++)
	{
		for(j=0;j<2;j++)
		{
			scanf("%lf",&list[i][j]);
		}
	}
	double max=B(n-1,V);//最多可以得到max元
	printf("%.0lf\n",max);
	return 0;
}
double B(int k,int c)
{
	if(k<0)
		return 0;
	else
	{
		if(list[k][0]>c)
			return B(k-1,c);
		else;
		{
			double result_1=B(k-1,c-list[k][0])+list[k][1],result_2=(B(k-1,c));//result_1为要这件商品并进行下一层递归 result_2则为不要这件商品
			double result=result_1>result_2?result_1:result_2;
			return result;
		}
	}
}

当数据过大时,运行时间会大大增加。
那么可以用数组的方法解决

测试数据

链接:https://pan.baidu.com/s/1u3tVniCGz4_lP8_9USFtgw
提取码:6666

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值