动态规划 01背包问题

**

动态规划 01背包递归算法 和非递归算法的理解分析 **

**

01完全背包问题描述

题目:一个旅行者有一个最多能放m公斤的背包,现有n件物品,他们的重量分别是w1,w2…,他们的价值分别是c1,c2… ,求旅行者最大能获得的总价值 (每个元素只有一个)
输入
第一行,输入物品的种类数
第二行开始:输入物品的体积 价值
第三行:输入背包的体积
输出 最大总价值
样例输入 输出在这里插入图片描述
这里列举具体的元素来分析一下计算过的过程
dp(n,ww)其中n代表的是物品的个数 ww代表的是背包的体积 dp(n,ww)代表的意思是 在背包容量为ww时从n个物品选出的价值的最大值 接下来举了一个具体的数据来分析一下
在这里插入图片描述
这样分析一下就很清楚了 递归有两个需要注意的地方
if(n0||ww0)return 0;//当体积或者可选的物品数目为零时就返回零
else if(v[n]>ww)//当前的元素的体积比背包的体积大的时候这个物品就不选 直接递归到下一个 return dp(n-1,ww);
else //return 选这个物品还是不选这个物品时值最大 返回最大的数值
递归过程就是这么简单
递归代码

在这里插入代码片`#include<stdio.h>
int dpp(int n, int *w, int *v, int ww)
{
	if (n == 0 || ww == 0)
		return 0;
	else if (w[n] > ww)
		dpp(n - 1, w, v, ww);
	else
	{
		int A = dpp(n - 1, w, v, ww - w[n]) + v[n];
		int B = dpp(n - 1, w, v, ww);
		return A > B ? A : B;
	}
}
int main()
{
	int n,i,w[100],v[100],ww,all;//w表示体积 v表示价值 ww代表的是现在剩下的体积
	printf("输入一共有多少种物品      ");
	scanf("%d",&n);
	for (i = 1; i <= n; i++)
	{
		printf("输入这种货物的 体积 价值 \n");
		scanf("%d%d",&w[i],&v[i]);
	}
	printf("输入背包的体积   ");
	scanf("%d",&ww);
	all = dpp(n,w,v,ww);
	printf("最大价值是   %d",all);
}

下面用到的数组和上面分析用到的数据是相同的
上面的是递归代码的分析 **其实动态规划就是递归的逆过程 从递归结束的条件出发 断的向后面推 是简单的填表的过程 **
这个表格要怎样填呢,首先填上递归结束的条件 然后按照递归的推导过程不断的填表
用一个二维数组来表示dp[i][j]其中 i 代表的是元素的个数 j 代表的是背包的体积 就是这么简单
在这里插入图片描述

非递归代码

在这里插入代码片`#include<stdio.h>
int main()
{
	int n, w[20], v[20], dpp[20][40],ww,i,j;//n代表的是总的物品数目 w代表质量 v代表价值  ww 代表背包的体积
	printf("输入有多少个元素   ");
	scanf("%d",&n);
	for (i = 1; i <= n; i++)
	{
		printf("输入该物品的 体积 价值 \n");
		scanf("%d%d",&w[i],&v[i]);
	}
	printf("输入背包的体积  \n");
	scanf("%d", &ww);

//递归结束的条件
	for (i = 0; i <= ww; i++)
	{
		dpp[0][i] = 0;//选择的物体为零个
	}
	for (i = 0; i <= n; i++)
	{
		dpp[i][0] = 0;//选择的体积为零
	}

//按照有条件来不断的填表
//递归条件理解透彻

	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= ww; j++)
		{
			if (w[i] > j)
				dpp[i][j] = dpp[i - 1][j];
			else
			{
				int A = dpp[i - 1][j - w[i]] + v[i];
				int B = dpp[i - 1][j];
				if (A > B)
					dpp[i][j] = A;
				else
					dpp[i][j] = B;
			}
		}
	}
	printf("最大的价值是多少 %d",dpp[n][ww]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值