动态规划(基础)

目录

一、算法思想

二、解题步骤 

三、神奇的兔子序列 

(一)问题

(二)递归公式

(三)以求解F(6)为例 

(四)代码

四、01背包问题

(一)算法思想 

(二)举例  

1. 有3种物品

2. 背包问题网格

3. 初始化第一列

4. 吉他行

5. 音箱行 

6. 电脑行

7. 总结

(三)核心代码  

(四)完整代码  


一、算法思想

  • 动态规划也是一种分治思想,但与分治算法不同的是,分治算法是把原问题分解成若干子问题,自顶向下求解各子问题,合并子问题的解,从而得到原问题的解。动态规划也是把原问题分解为若干子问题然后自底向上,先求解最小的子问题,把结果存储在表格中,再求解大的子问题时,直接从表格中查询小的子问题的解,避免重复计数,从而提高算法效率。

二、解题步骤 

(1)分析最优解的结构特征

(2)建立最优值的递归式

(3)自底向上计算最优值,并记录

(4)构造最优解

三、神奇的兔子序列 

(一)问题

前两个月都是1对兔子,从第3个月开始,当月的兔子数等于前两个月的兔子数,求解第n个月的兔子数量?

(二)递归公式

 

(三)以求解F(6)为例 

  • 利用动态规划求解的时候,记录结果,重复问题只需要求解依次即可

动态规划(基础)_第1张图片

(四)代码

int Fib(int n)
{
	if (n < 1)
		return -1;
	else
	{
		vectorF(n+1);
		F[0]=0;
		F[1]=1;
		F[2]=1;
		for (int i = 3; i <= n; i++)
		{
			F[i] = F[i - 1] + F[i - 2];
		}
		return F[n];
	}
}

四、01背包问题

(一)算法思想 

  • 用数组dp[i][j]表示从下标为0到i-1的物品里任意选取,然后放进容量为j的背包中,背包所能装入的最大价值。

对于一个物品i,要么能放入背包,要么不能放入背包:

  • 第一种情况:物品i的重量w[i]大于背包容量j的时候,此时物品i不能放入背包中,那么需要从剩下0到i-1个物品中任意选取放入背包中,此时背包所能装入最大价值为dp[i][j]=dp[i-1][j]
  • 第二种情况:物品i的重量w[i]小于背包容量的时候,此时物品i能放入背包中,但是可以选择将物品i不放入背包或者放入背包。第二种情况又分以下两种:
  • 1.选择不将物品i放入背包的时候,那么从剩下的0到i-1个物品中任意选取价值大的物品放入背包中,此时背包所能装入最大价值为dp[i][j]=dp[i-1][j]
  • 2.选择将物品i放入背包的时候,需要先将物品i放入背包,那么背包剩余容量为j-w[i]
  • 此时从剩下的0到i-1个物品中任意选取价值大的物品放入背包中,背包所能装入最大价值为dp[i][j]=dp[i-1][j-w[i]]+v[i]
  • 那么物品最大价值为dp[i][j]=max\left \{ dp[i-1][j],dp[i-1][j-w[i]]+v[i] \right \}

所以背包所能装入最大价值为:

dp[i][j]=\begin{cases}dp[i-1][j] &,0<= j<w[i]\\max \left \{ dp[i-1][j] ,dp[i-1][j-w[i]]+v[i]\right \}&, j>=w[i]\end{cases}

(二)举例  

1. 有3种物品

物品 价值 重量
吉他 1500美元 1磅
音箱 3000美元 4磅
笔记本电脑 2000美元 3磅

2. 背包问题网格

 动态规划(基础)_第2张图片

3. 初始化第一列

  • 背包容量为0,意味着吉他,音箱,电脑都不能装入背包,所有此时背包最大价值均为0 

动态规划(基础)_第3张图片

4. 吉他行

 1.  第2个单元格表示背包的容量为1磅。吉他的重量也是1磅,这意味着它能装入背包!

 动态规划(基础)_第4张图片

2. 之后背包容量为2磅,3磅,4磅也能装下

动态规划(基础)_第5张图片

 3. 表明若一个背包容量为4磅,可在其中装入的商品的最大价值为1500美元

5. 音箱行 

动态规划(基础)_第6张图片

 动态规划(基础)_第7张图片

 

动态规划(基础)_第8张图片

  • 更新最大值:表明若一个背包容量为4磅,可在其中装入的商品的最大价值为3000美元  

6. 电脑行 

动态规划(基础)_第9张图片

 动态规划(基础)_第10张图片

 动态规划(基础)_第11张图片

7. 总结

动态规划(基础)_第12张图片

(三)核心代码  

template
void Knapsack(int bagW,int n)
{
	vectorvalue(n);//存放物品价值
	vectorweight(n);//物品数量
	Init(n,value,weight);//初始化物品信息
	vector>dp(n,vector(bagW+1,0));//背包最大价值

	for (int i = 0; i < n; i++)//初始化第一列
	{
		dp[i][0] = 0;
	}
	for (int j = 1; j <= bagW; j++)//初始化第一行
	{
		if (j < weight[0])//背包容量小于物品重量
			dp[0][j] = 0;
		else
			dp[0][j] = value[0];
	}

	for (int i = 1; i < n; i++)//i是物品序号
	{
		for (int j = 1; j <=bagW; j++)//j表示背包容量
		{
			if (j < weight[i])//容量为j的背包装不了物品i
				dp[i][j] = dp[i - 1][j];//此时背包最大价值为前i-1个物品的最大价值
			else
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
		}
	}
	cout << "背包最大价值:"<

(四)完整代码  

#include
#include
using namespace std;
template
void Init(int n,vector&v,vector&w)//物品初始化
{
	cout << "依次输入物品的价值和重量:"<> v[i] >> w[i];
	}
	//直接初始化物品
	//vectorvalue{ 1501.6,3000,2000.8 };
	//v = value;
	//vectorweight{ 1,4,3 };
	//w = weight;
}
template
void Knapsack(int bagW,int n)
{
	vectorvalue(n);//存放物品价值
	vectorweight(n);//物品数量
	Init(n,value,weight);//初始化物品信息
	vector>dp(n,vector(bagW+1,0));//背包最大价值

	for (int i = 0; i < n; i++)//初始化第一列
	{
		dp[i][0] = 0;
	}
	for (int j = 1; j <= bagW; j++)//初始化第一行
	{
		if (j < weight[0])//背包容量小于物品重量
			dp[0][j] = 0;
		else
			dp[0][j] = value[0];
	}

	for (int i = 1; i < n; i++)//i是物品序号
	{
		for (int j = 1; j <=bagW; j++)//j表示背包容量
		{
			if (j < weight[i])//容量为j的背包装不了物品i
				dp[i][j] = dp[i - 1][j];//此时背包最大价值为前i-1个物品的最大价值
			else
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
		}
	}
	cout << "背包最大价值:"<(4,3);//背包最大容量为4,物品个数为3
	return 0;
}

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