初识动态规划——0 1背包问题

动态规划(简称DP)是一种将复杂问题分解成很多子问题,并将子问题的求解结果存储起来避免重复求解的一种算法。动态规划一般用来解决最优问题。而解决问题的过程,需要经历多个决策阶段。每个决策阶段都对应着一组状态。最后通过一组决策序列(动态转移方程),产生最终期望的最优解。(看不懂概念?)

我也是


简单说jiu's利用历史记录避免重复计算,用空间换时间,一般使用一维或二维数组保存。

解决动态规划步骤大致分五部(动规五部曲)

1.了解dp数组的含义

2.列出递推公式

3.dp数组初始化

4.遍历顺序

5.打印dp数组(用于检查是否有错误,一般省略)

下面根据例题熟悉解题步骤。

题目描述


辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?

输入

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

输出

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

样例输入 
70 3
71 100
69 1
1 2
样例输出 
3

 解题思路

按照动态规划5部曲。

第一步:首先要知道dp数组的含义,按照上面例题我们定义dp数组如:

dp[i][j]表示的就是在时间j的范围内取编号为0~i的药草的最大价值。(了解dp数组的含义方便我们理解代码,也是解决动态规划的重点)

第二步:根据题目推导出递推公式(解决问题的核心),根据上面例题每株草药有3种情况,  1.时间不够不能取

2.时间够可以取但不取 3.时间够可以取

如果时间够dp[i][j]=max(dp[i-1][j-a[i] ]+b[i],dp[i-1][j])(a[i]表示取药草i所需要的时间,b[i]表示价值)

如果时间不够 dp[i][j]=dp[i-1][j]

第三步:dp数组初始化

首先为什么要初始化?很简单因为dp数组后面的是由前面的推导出来的如果一开始没有值,那后面结果很可能会出错,当然这要根据题目,在这一题初始化就是第0行和第0列,第0列表示用有时间为0那当然取得的草药价值为0了所以进行初始化,第0行表示没有草原,那取得的价值也为0了

第四步:遍历顺序

这题由于从前面推出后面遍历顺序那也是如此

第五步:打印dp数组

这一步大部分可以省略如果你代码出现结果错误,可以打印dp数组看看哪里错了

下面上代码:

#include
int max(int a, int b)//找出两者中较大值
{
	if (a >= b)
		return a;
	else
		return b;
}
int main()
{
	int t, m, s[200] = { 0 }, v[200] = { 0 }, i, j, dp[111][1011] = { 0 };
	//s数组储存采摘每株草药的时间,v表示每株草药的价值
	scanf("%d %d", &t, &m);//输入总时间t,草药的数量m
	for (i = 1; i <= m; i++)
	{
		scanf("%d %d", &s[i], &v[i]);
	}
	for (i = 1; i <= m; i++)//遍历每种草药
	{
		for (j = 1; j <= t; j++)//遍历每个时间
		{
			if (j >= s[i])//如果时间够
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - s[i]] + v[i]);//取时间够的情况下,摘与不摘取价值更大的
			else//时间不够的情况
				dp[i][j] = dp[i - 1][j];
		}
	}
	printf("%d", dp[m][t]);
	return 0;
}

总结

关于动态规划还有很多种题型,需要多学多练才能掌握,继续加油!

初识动态规划——0 1背包问题_第1张图片

你可能感兴趣的:(动态规划,算法)