动态规划DP专题

 动态规划五部曲:

定含义,定递推,初始化,定顺序,举例验证

  • 例题

动态规划五部曲:

定义一个一维数组来记录不同楼层的状态

1.确定dp数组以及下标的含义

dp[i]:爬到i层的方法数

2.根据1确定递推公式

dp[i]=dp[i-1]+dp[i-2]

3.dp数组如何初始化

dp[0]不用管它是几,因为题目说i是正整数;所以初始化dp[1]=1,dp[2]=2,然后从i=3开始递推。

4.确定遍历顺序

从递推公式dp[i]=dp[i-1]+dp[i-2]得知遍历是从前往后。

5.举几个例子推导验证dp数组

代码示例:

#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int> dp(n+1);

int main()
{
	dp[1]=1;
	dp[2]=2;
	cin>>n;
	for(int i=3; i<=n; i++)
	{
		dp[i]=dp[i-1]+dp[i-2];
	}
	cout<<dp[n]<<endl;
}
  • 例题

 动态规划五部曲:

1.确定dp数组以及下标的含义

dp[m][n]:在一个m行n列的迷宫中走到final的路径数

2.根据1确定递推公式

dp[m][n]=dp[m-1][n]+dp[m][n-1];

3.dp数组初始化

dp[1][2,3,4,5,,,n]=1,dp[2,3,4,5,,,m][1]=1,dp[2][2]=2

4.确定遍历顺序

由递推公式可知:从上到下,从左到右

5.举例验证推导dp数组

#include<iostream>
#include<vector>
using namespace std;
int m,n;
int main()
{
	cin>>m>>n;
	vector<vector<int> > dp(m,vector<int>(n,0));
//注意这里的<vector<int> >,右边两个>要加空格,否则被认作operator而报错

	for(int i=0; i<m; i++)
	{
		dp[i][0]=1;
	}
	for(int i=0; i<n; i++)
	{
		dp[0][i]=1;
	}

//这里要是先按从上到下的顺序赋值,就把m和n互换,然后别忘了同时换i和j,因为ij对应的含义发生了改变 
	for(int i=1; i<m; i++)
	{
		for(int j=1; j<n; j++)
		{
			dp[i][j]=dp[i-1][j]+dp[i][j-1];
		}
	}
	
//	for(int i=0; i<m; i++)
//	{
//		for(int j=0; j<n; j++)
//		{
//			cout<<dp[i][j]<<" ";
//		}
//		cout<<endl;
//	}
	cout<<dp[m-1][n-1]<<endl;
}

Debug测试用代码:

	for(int i=0; i<m; i++)
	{
		for(int j=0; j<n; j++)
		{
			cout<<dp[i][j]<<" ";
		}
		cout<<endl;
	}

  • 例题

 

1.定含义
//dp[i][j] 从(0,0)到(i,j)的不同的路径
2.定递推
//if((i,j)!=障碍)
//dp[i][j]=dp[i-1][j]+dp[i][j-1]
//else
//dp[i][j]=0
3.初始化
//dp[0][0,1,2,3,,,j]=0;
//dp[0,1,2,3,,,i][0]=0;
4.定顺序
//由递归顺序可知他就是按照从左到右从上到下的顺序

#include<iostream>
#include<algorithm>
#include<vector>
int m,n;

//1.定含义
//dp[i][j] 从(0,0)到(i,j)的不同的路径
//2.定递推
//if((i,j)!=障碍)
//dp[i][j]=dp[i-1][j]+dp[i][j-1]
//else
//dp[i][j]=0
//3.初始化
//dp[0][0,1,2,3,,,j]=0;
//dp[0,1,2,3,,,i][0]=0;
//4.定顺序
//由递归顺序可知他就是按照从左到右从上到下的顺序

using namespace std;
int main()
{
	cin>>m>>n;
	vector<vector<int> > data(m,vector<int>(n,0));
	vector<vector<int> > dp(m,vector<int>(n,0));

	for(int i=0; i<m; i++)
	{
		for(int j=0; j<n; j++)
		{
			cin>>data[i][j];
		}
	}


//
	dp[0][0]=1;
	for(int j=1; j<n; j++)
	{
		if(data[0][j]==1)
		{
			dp[0][j]=0;
		}
		else
			dp[0][j]=dp[0][j-1];
	}

	for(int i=1; i<m; i++)
	{
		if(data[i][0]==1)
		{
			dp[i][0]=0;
		}
		else
			dp[i][0]=dp[i-1][0];
	}



	//if((i,j)!=障碍)
//dp[i][j]=dp[i-1][j]+dp[i][j-1]
//else
//dp[i][j]=0
	
	for(int i=1; i<m; i++)
	{
		for(int j=1; j<n; j++)
		{
			if(data[i][j]==1)
			{
				dp[i][j]=0;
			}
			else
				dp[i][j]=dp[i-1][j]+dp[i][j-1];
		}
	}


//	for(int i=0; i<m; i++)
//	{
//		for(int j=0; j<n; j++)
//		{
//			cout<<dp[i][j]<<" ";
//		}
//		cout<<endl;
//	}
	
	cout<<dp[m-1][n-1]<<endl;

}

  •  例题

 

1.dp[i]表示数i的拆分后的最大积 
2.j从1到i 
        dp[i]=max(j*(i-j),j*dp[i-j])
3.初始化dp[2]=1 
4.顺序从左到右 

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

//1.dp[i]表示数i的拆分后的最大积 
//2.j从1到i 
//dp[i]=max(j*(i-j),j*dp[i-j])
//3.初始化dp[2]=1 
//4.顺序从左到右
int main()
{
	int n;
	cin>>n;
	vector<int> dp(n+1);
	dp[1]=1;
	dp[2]=1;
	for(int i=3;i<=n;i++)
	{
		for(int j=1;j<=i;j++)//j的遍历上限当然可以再优化一下,这里就不了
		{
			dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));
			//比较dp[i]为了在递推公式推导的过程中,每次计算dp[i],取最大的而已。
		}
	}
	
//	for(int i=1;i<=n;i++) 
//	{
//		cout<<dp[i]<<" ";
//	}
	cout<<dp[n]<<endl; 
}

 

  • 例题

//n        物品数
//w        背包重量上限
//w[i]     第i件物品的重量
//value[i] 第i件物品的价值

1.

dp[i][j]   从下标0~i的物品任取,放到容纳重量为j的背包,价值总和最大是多少

2.
//dp[i][j]=dp[i-1][j]
//dp[i][j]=dp[i-1][j-w[i]]+value[i]

3.

最左行,都是零,最上一行,有变化。

4.

左上方到右下方

#include<iostream>
#include<algorithm>
#include<vector>
//纯01背包
//n        物品数
//w        背包重量上限
//w[i]     第i件物品的重量
//value[i] 第i件物品的价值

//dp[i][j]   从下标0~i的物品任取,放到
//           容纳重量为j的背包,价值总和
//		     最大是多少
//dp[i][j]=dp[i-1][j]
//dp[i][j]=dp[i-1][j-w[i]]+value[i]
using namespace std;
int main()
{
	int a[]={1,3,4};
	int b[]={15,20,30};
	vector<int> weight(a,a+3);
	vector<int> value(b,b+3);
	int max_weight=4;
	int n=weight.size();
	
	vector<vector<int> > dp(n,vector<int>(max_weight+1,0));
	
	//第一行赋值,第一列不用赋值 
	for(int j=weight[0];j<=max_weight;j++)
	{
		dp[0][j]=value[0];
	}
	
	for(int i=1;i<weight.size();i++)
	{
		for(int j=0;j<=max_weight;j++)
		{
			if(j<weight[i])
				dp[i][j]=dp[i-1][j];//排除j-weight[i]为负数出错的情况 
			else
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
		}
	}
	
//	for(int i=0;i<weight.size();i++)
//	{
//		for(int j=0;j<=max_weight;j++)
//		{
//			cout<<dp[i][j]<<" ";
//		}
//		cout<<endl;
//	}
	
	cout<<dp[weight.size()-1][max_weight]<<endl;
}

 

  • 例题

参考于公众号:代码随想录

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

东部花园

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

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

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

打赏作者

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

抵扣说明:

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

余额充值