动态规划之背包问题篇

动态规划(Dynamic--Planning),简称DP。

一、求解背包问题的算法归纳——以背包问题为例

1)如果装不下当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。

2)如果装得下当前物品。

假设1 :装当前物品,在给当前物品预留了相应空间的情况下,前n-1 个物品的最佳组合加上当前物品的价值就是总价值。

假设2:不装当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是-样的。

选取假设1和假设2中较大的价值,为当前最佳组合的价值。

以二维数表为例,则求解过程是从左至右,从上至下:

        即先求只装入1个物品时,对应1个容量时的最大价值,再增加容量继续求此时对应的最大价值,直到容量达到MAX,再增加装入物品的数量,重复上述过程,直到物品数量为MAX时,求解完毕。

二、回溯背包物品的算法归纳——求价值最大时是装了哪些物品

        我们可以看作是求最优解的逆过程,即先从数表的右下角开始回溯,如果发现前n个物品最佳组合的价值和前n-1个物品最佳组合的价值一样,说明第n个物品没有被装入。否则,第n个物品被装入。当物品编号为0时,即没有物品需要被装入,说明回溯已经结束,根据标识的结果即可得到装入了哪些物品。

实战例题:采药 - C语言网 (dotcpp.com)

输入格式

输入第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

演示代码:

#include<iostream>
using namespace std;

int t[101];  //存放采每种药材的时间
int v[101];  //存放每种药材的价值
int dp[101][1001];  //初始化dp状态转移数组
int max(int a, int b)
{
	return a > b ? a : b;
}
int main()
{
	int T, M;
	cin >> T >> M;
	int i, j;
	//另一种初始化数组为0的方法,调用memset()函数 
	//int dp[M + 1][T + 1];
	//memset(dp, 0, sizeof(dp));
	for(i = 1; i <= M; i++)
	{
		cin >> t[i] >> v[i];
	}
	for(i = 1; i <= M; i++)
	{
		for(j = 1; j <= T; j++)
		{
			if(t[i] > j)
			{
				dp[i][j] = dp[i - 1][j];
			}
			else
			{
				dp[i][j] = max( (dp[i - 1][j]), (dp[i - 1][j - t[i]] + v[i]) );
			}
		}
	}
	cout << endl << dp[M][T];
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PL_涵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值