借鉴了博客:
动态规划: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];
}