动态规划问题一般解决框架——以及一些例题解法

借鉴了博客:
动态规划:https://blog.csdn.net/zw6161080123/article/details/80639932
背包问题:https://blog.csdn.net/chanmufeng/article/details/82955730
算法实现的步骤

1、创建一个一维数组或者二维数组,保存每一个子问题的结果。

2、设置数组边界值,一维数组就是设置第一个数字,二维数组就是设置第一行跟第一列的值。

3、找出转换方程,也就是说找到每个状态跟他上一个状态的关系,根据状态转化方程写出代码。

4、返回需要的值,一般是数组的最后一个或者二维数组的最右下角。

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
// 动态规划问题的算法一般步骤

//1、创建一个以为或者二维数组,用以保存子问题的结果
//2、设置数组的边界值,一维数组就是设置第一个数字,二维数组就是设置第一行和第一列的值
//3、找出状态转换方程,也就是找到关系方程式
//4、返回需要的值,一般是数组的最后一个或者二维数组的最右下角

//--------------------------------------------------------------------------------------
//--------------斐波那契数列------------------------------------------------------------

 static int solutionfib(int n)
{
	if (n < 2) return n;
	else
	{
		int *result= new int[n + 1];//1、创建一个以为或者二维数组,用以保存子问题的结果
		result[0] = 0;
		result[1] = 1;//2、设置数组的边界值,一维数组就是设置第一个数字,二维数组就是设置第一行和第一列的值
		for (int i = 2; i <= n; i++)
		{
			result[i] = result[i - 1] + result[i - 2];//3、找出状态转换方程,也就是找到关系方程式
		}
		return result[n];//4、返回需要的值,一般是数组的最后一个或者二维数组的最右下角
	}
}


 //-------------------------------------------------------------------------------------------------------
 //----------数组最大不连续递增子序列---------------------------------------------------------------------

 static int maxchildarray(vector<int> a)
 {
	 int size = a.size();
	 int* temp = new int[size];           //创建一个一维数据,并初始化为1,用以保存最大不连续递增子序列的值
	 for (int i = 0; i < size; ++i)
		 temp[i] = 1;
	 for (int i = 1; i < size; ++i)     //核心算法部分
	 {
		 for (int j = 0; j < i; ++j)
		 {
			 if (a[i] > a[j] && temp[j] + 1 > temp[i]) //判断若数组递增且对于其子序列temp[i+1]得知大于temp[i]保存的值,更新temp[i]
				 temp[i] = temp[j] + 1;
		 }
	 }
	 int max = 0;
	 for (int i = 1; i < size; ++i)  //求出最大的不连续递增子序列的值 并返回
	 {
		 if (temp[i] > max)
			 max = temp[i];
	 }
	 return max;
 }
 //-------------------------------------------------------------------------------------------------------
 //--------------数字塔的最大路径问题---------------------------------------------------------------------
 // 方法一,直接按动态规划方法解 
 static int minNumberinRotateArray1(vector<vector<int>> n)
 {
	 int MAX = 0;
	 int size = n.size();
	 int** mm = new int* [size];
	 for (int i = 0; i < size; ++i)  //定义二维动态数组
		 mm[i] = new int[size];
	 mm[0][0] = n[0][0];           //设定边界值
	 for (int i = 1; i < size; ++i)
	 {
		 for (int j = 0; j <= i; ++j)
		 {
			 if (j == 0)
			 {
				 mm[i][j] = mm[i - 1][j] + n[i][j]; //若是第一列,直接加上面的数字
			 }
			 else  //若非第一列,比较他上面和他上面左面的数字谁最大
			 {
				 mm[i][j] = max(mm[i - 1][j - 1], mm[i - 1][j]) + n[i][j];
			 }
			 MAX = max(MAX, mm[i][j]);
		 }
	 }
	 return MAX;
 }
 //优化:动态规划中每一个需要创建一个二维数组扽解法,都可以换成只创建一个一维数组的滚动数组解法
 //      这样可以降低空间复杂度。

 //方法二:利用一维滚动数组的方式的最大路径问题,优化了空间复杂度
 static int maxNumberinRotateArray2(vector < vector<int>> vec)
 {
	 int val = 0;
	 int* p = new int[vec.size()];
	 int size = vec.size();
	 p[0] = vec[0][0];
	 for (int i = 1; i < size; ++i)
	 {
		 for (int j = i; j >= 0; j--)//从最后一位数开始,防止所需要的上一个数组的值被覆盖
		 {
			 if (j == i)
			 {
				 p[j] = p[j - 1] + vec[i][j];
			 }
			 else if (j == 0)
			 {
				 p[j] = p[j] + vec[i][j];
			 }
			 else
			 {
				 p[j] = max(p[j], p[j - 1]) + vec[i][j];
			 }
		 }
	 }
	 for (int i = 0; i < size; ++i) //从最后的数组中选出最大的值,即为所需要的结果
		 if (p[i] > val)
			 val = p[i];
	 return val;
 }
 //方法三:自下而上的滚动数组的方法求解(最简最好的方法)
 static int  maxNumberinRotateArray3(vector<vector<int>> vec)
 {
	 int n = vec.size();
	 int* p = new int[n];
	 for (int i = 0; i < n; ++i)
	 {
		 p[i] = vec[n - 1][i];
	 }
	 for (int i = n - 2; i >= 0; i--)
	 {
		 for (int j = 0; j <= i; j++)
		 {
			 p[j] = max(p[j], p[j + 1]) + vec[i][j];
		 }
	 }
	 return p[0];
 }


//--------------------------------------------------------------------------------------------------------
//--------------------------------两个字符串的的最大公共子序列--------------------------------------------
//子传播要求在原字符串中是连续的,而子序列则只需保持相对位置一致,并不要求连续 

 static int MaxTwoArraySameOrderMethoh(string str1, string str2)
 {
	 int m = str1.size();
	 int n = str2.size();
	 /*定义一个二维数据保存公共子序列长度
	 dp[i][j]表示字符串1从头开始长度的i,字符串2从头开始长度是j,*/
	 int** dp = new int* [m + 1];
	 for (int i = 0; i < m+1; ++i)
	 {
		 dp[i] = new int[n + 1];  //创建一个二维数组
	 }
	 for (int i = 0;i <= m; ++i)
	 {
		 dp[i][0] = 0;
	 }
	 for (int i = 0; i <= n; ++i)
	 {
		 dp[0][i] = 0;
	 }
	 for (int i = 1; i <= m; ++i)
	 {
		 for (int j = 1; j <= n; ++j)
		 {
			 if (str1[i - 1] == str2[j - 1])
				 dp[i][j] = dp[i - 1][j - 1] + 1;
			 else
			 {
				 dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
			 }
		 }
	 }
	 return dp[m][n];
 }

 //-----------------换一种思路,用一下递归方法求解---------------------
 //代码非常简便,但是时间复杂度相当高,应该的O(n^2)
 int LCS(string s1, string s2, int m, int n)
 {
	 if (n == 0 || m == 0) return 0;
	 if (s1[m - 1] == s2[n - 1]) return LCS(s1, s2, m - 1, n - 1)+1;
	 else
		 return max(LCS(s1, s2, m - 1, n), LCS(s1, s2, m, n - 1));
 }
 //-------------------------背包问题-----------------------------------
 //有n件物品取出若干件放在容量为W的背包里,每件物品的体积为W1,W2...Wn,与之对应的价值为P1,P2..Pn.
 //求背包能容纳的最大价值
 static int PackageHelper(int n, int w[], int p[], int v)
 {
	 int ** dp = new int* [n + 1];   //dp代表最大的价值。
	 for (int i = 0; i < n + 1; ++i)   //设置一个二维矩阵,横坐标为从第一个物品开始到第n个物品
	 {                                //纵坐标为背包还剩余多少容量。
		 dp[i] = new int[v + 1];
	 }
	 for (int i = 1; i < n + 1; ++i)
	 {
		 for (int j = 1; j < v + 1; ++j)
		 {
			 if (j >= w[i]) //若背包还能放下东西,东西放进去,容量减小,价值增加
				 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + p[i]);
			 else
				 dp[i][j] = dp[i - 1][j];
		 }
	 }
	 return dp[n][v];
 }
 //优化:滚动数轴,只用一维数组去存值
 static int  Package(int n, int w[], int p[], int v)
 {
	 int* dp = new int[v+1];
	 for (int i = 1; i < n + 1; ++i)
	 {
		 for (int j = v; j > 0; j--)
		 {
			 if (j >= w[i])
			 {
				 dp[j] = max(dp[j], dp[j - w[i]] + p[i]);
			 }
			 else
				 dp[j] = dp[j];
		 }
	 }
	 return dp[v];
 }



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值