开心的小明——动态规划

问题描述:

小明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早小明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。

于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1j2,……,jk,则所求的总和为:

v[j1]*w[j1]+v[j2]*w[j2]+ +v[jk]*w[jk]。(其中*为乘号)

请你帮助小明设计一个满足要求的购物单。

初看这个问题,和0-1背包问题很相似,可以采用动态规划方法来求解:

什么是动态规划(DP)?
非常重要!,不要认为概念不重要,理解的深刻,你才知道对于什么样的问题去考虑有没有动态规划的方法,以及如何去使用动态规划
1)动态规划是运筹学中用于求解决策过程中的最优化数学方法。 当然,我们在这里关注的是作为一种算法设计技术,作为一种使用多阶段决策过程最优的通用方法它是应用数学中用于解决某类最优化问题的重要工具。
2)如果问题是由交叠的子问题所构成,我们就可以用动态规划技术来解决它,一般来说,这样的子问题出现在对给定问题求解的递推关系中,这个递推关系包含了相同问题的更小子问题的解。动态规划法建议,与其对交叠子问题一次又一次的求解,不如把每个较小子问题只求解一次并把结果记录在表中(动态规划也是空间换时间的),这样就可以从表中得到原始问题的解。

由于动态规划具备最优子结构的性质,这意味着它属于递归的一种。

#include "OJ.h"
#include <stdlib.h>
int** initStateMatrix(int*p)
{
	int** StateMatrix=(int **)malloc(sizeof(int*)*(*(p+1)));
	int No=0,money=0;
	//int 状态矩阵
	for(No=0;No<=*(p+1);No++)
	{
		StateMatrix[No]=(int*)malloc(*p*sizeof(int));
		for(money=0;money<=*p;money++)
		{
			StateMatrix[No][money]=0;
		}
	}
	for(No=1;No<=*(p+1);No++)
	{
		for(money=1;money<=*p;money++)
		{
			if(*(p+No*2)<=money)
			{
				StateMatrix[No][money]=StateMatrix[No-1][money]>(StateMatrix[No-1][money-*(p+No*2)]+(*(p+No*2)*(*(p+No*2+1))))?StateMatrix[No-1][money]:StateMatrix[No-1][money-*(p+No*2)]+(*(p+No*2)*(*(p+No*2+1)));
			}
			else StateMatrix[No][money]=StateMatrix[No-1][money];
		}
	}
	return StateMatrix;
} 
/*
功能:

输入参数:int*p 指向二维数组的首地址,该二维数组第0行的两个数分别表示:总钱数<30000,和希望购买物品的个数<25;
          该数组从第1行到第m行(1<=j<=m)中给出了编号为j的物品的基本数据,每行有2个非负整数,
		  表示该物品的价格(<=10000)和该物品的重要度(1~5)。

		  GetResult表示不超过总钱数的物品的价格与重要度乘积的总和的最大值(<100000000)。

		  不需做入参检查,测试用例可以保证~
		  
    例如:4000 8(第0行)
		  821 3  (第1行)
		  422 5
		  458 5
		  500 3
		  200 2
		  430 4
		  530 3
		  239 3
		 
		  则表示 总钱数为4000,希望购买物品个数为8个,因此从第1行到第8行表示编号为j的物品的价格及物品的重要度。
	 	
          

	 		
返回值:无

温馨提示:根据题意可知,该二维数组只有两列,且行数为第0行的第二个元素数值+1;入参p不能按照二维数组的方法来取值,要将
          二维的转换成一维的哦~

*/

void GetResult(int*p,int& Get_Result)
{	 
    //	在这里实现功能
	int i;
	int** StateMatrix=initStateMatrix(p);
	for(int i=0;i<=*(p+1);i++)
	{
		Get_Result=StateMatrix[i][*p]>Get_Result?StateMatrix[i][*p]:Get_Result;
	}
} 

	

<think>嗯,用户让我用C++专家的身份来教孩子动态规划。这有点挑战,因为孩子可能对编程概念不熟悉,需要简单易懂的例子。首先,我得想一个适合孩子的例子,比如数楼梯或者分糖果,这样他们容易理解。 动态规划的核心是分解问题和记住中间结果。我得用孩子能理解的比喻,比如把大问题拆成小问题,然后用记事本记住已经解决的步骤。比如爬楼梯,每次只能走1或2步,问有多少种方法。这可以用递归解释,但递归会有重复计算,这时候引入记忆化,也就是记事本记录已经算过的台阶数,避免重复计算。 然后,可能需要过渡到递推的方法,比如自底向上,从底层开始计算每一层的方法数。这样孩子可以直观地看到每一步的结果,而不是递归的抽象过程。 接下来,我需要确保用C++代码示例,比如斐波那契数列的动态规划实现。但代码要简单,用循环而不是递归,这样孩子更容易理解循环的步骤。同时,解释代码中的数组如何存储中间结果,避免重复计算。 可能的问题是如何让孩子理解状态转移方程,比如f(n) = f(n-1) + f(n-2)。可以用具体的例子,比如走到第3阶的方法等于走到第2阶和第1阶的方法之和,因为最后一步可以是1步或2步。 另外,要考虑孩子的注意力集中时间,例子要生动有趣,可能用动画或图画辅助,但这里只能文字描述,所以例子要足够简单明了。 最后,用户可能需要后续问题,比如动态规划与分治的区别、记忆化搜索、状态转移方程等,但需要保持问题适合孩子的理解水平,或者更基础的DP问题。</think><< 如何用孩子能理解的方式讲解动态规划: 1. 用故事引入问题:比如"小明要爬10级台阶,每次只能走1步或2步,有多少种走法?" 2. 分解问题:把大问题拆成小问题(比如先解决3级台阶的问题) 3. 引入"记忆"概念:用画图展示重复计算,然后说"我们可以用笔记本记住算过的台阶" 4. 递推演示:用表格记录每级台阶的走法数(展示自底向上的计算过程) 示例代码(青蛙跳台阶问题): ```cpp #include <iostream> using namespace std; int count_ways(int n) { if(n <= 2) return n; int dp[n+1]; dp[1] = 1; dp[2] = 2; for(int i = 3; i <= n; i++) { dp[i] = dp[i-1] + dp[i-2]; } return dp[n]; } int main() { cout << "爬5级台阶有 " << count_ways(5) << " 种方法" << endl; // 输出:爬5级台阶有 8 种方法 return 0; } ``` 解释说明: 1. 我们把大问题分解成小台阶的计算 2. 用dp数组记录每个台阶的走法数(记忆化) 3. 当前台阶的走法=前一级走法+前前级走法(因为最后一步可以是1步或2步) 4. 通过循环自底向上计算,避免递归的重复计算 >>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值