动态规划入门1---数字三角形--C++

作为一个菜鸡,研究了几天的DP,把经典例题研究了几遍,现在,我在这发表一下自己的菜鸡见解,记录下我对DP的理解。


DP里面少不了递归,当然也能混在搜索里面构成记忆化搜索作为优化,也可以用递推来动态规划。
具体你要我说动态规划是个什么东西,我也只能说说自己的理解:

满足条件:

  • 最优子结构情况 (一个问题可以拆分成子问题来解决。很多的DP都涉及到了01背包问题这种思想,比如对待这个状态的解决方法,他的下一个状态是,得到与抛弃两种情况的和,即为背包问题的拿与不拿)
  • 无后效性(即当前情况的结果对后面的结果没有影响,也就是说后面值的改变对当前情况没有任何影响)

几种情况:(暂时就先这么写,日后等我见识了更多的dp种类,我再来改)

  • 记忆化递归————作为递归代码的一种优化,减少时间复杂度。
  • 记忆化搜索————在DFS这种极其暴力的情况下,爆栈的情况很容易发生,采用记忆化的情况来处理,也算是一种动态规划。
  • 分支递归————这个就是背包问题的概述,取或者不取的问题,一分二,二分四,2的n次方复杂度。这时候也是要记忆化来优化
  • 递推—————这种题目可以用滚动数组来做,做到不断的覆盖。

综上,这个动态规划很重要的就是记忆化的操作。
接下来是我学习DP的第一道入门题目


动态规划入门1---数字三角形--C++_第1张图片输入格式:
5//三角形的行数。下面是三角形
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出最大和


题目解析:
假定maxsum(i,j)表示从i,j这个点到最后一行的最大和
D(i,j)表示i行j列的数字大小
先设初始值i与j都为0,表示从(0,0)这个点开始到最后一行的最大和。
那么可以分解为(0,0)的下和右下两个点到底部的最大和,其中最大的一个数加上D(0,0)本身的数字
能够得到:maxsum(i,j)=maxsum( maxsum(i-1,j) , maxsum(i-1,j-1) )+D(i,j)

这样就能得到初步代码


#include
using namespace std;
#define MAX 101 
int D[MAX][MAX];
int n;
int maxsum(int i,int j)
{
	if(i==n)
	return D[i][j];
	int x=maxsum(i+1,j);
	int y=maxsum(i+1,j+1);
	return max(x,y)+D[i][j];
}
int main()
{
	int i,j;
	cin>>n;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=i;j++)
		{
			cin>>D[i][j];
		}
	}
	cout<<maxsum(1,1)<<endl;
} 

上面这个代码对于n比较小的情况是可行的,但是,时间复杂度是2的n次方级别,因为其中递归调用涉及到了重复计算,比如下图的红色数字为计算次数。
动态规划入门1---数字三角形--C++_第2张图片

那么怎样进行优化呢?

因为是重复计算,所以我们只需要对于重复计算的情况保存下来,下次要用到这个重复计算的值的时候,直接调用就可以了。这样就会大大节省时间。优化时间复杂度。

优化步骤:

  • 建立数组存放已经算出来的值,并且全部初始化。
  • 寻找递归终止条件

以下是优化代码


#include 
#include
using namespace std;
int D[105][105];
int n;
int maxarray[105][105]={0};
int MAX;
int dg(int x,int y)
{
	if(maxarray[x][y])return maxarray[x][y];//如果这种情况计算过,直接返回 
	if(x==n)maxarray[x][y]=D[x][y];//如果当前行数就是最后一行,那么只需要把当前位置的数字赋值给最大的情况 
	else 
	{
		int p=dg(x+1,y);
		int q=dg(x+1,y+1);		
		maxarray[x][y]= max(p,q)+D[x][y];
	}
	return maxarray[x][y];
	
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<=i;j++)
		{
			cin>>D[i][j];
		}
	}
	cout<<dg(0,0);
}

你可能感兴趣的:(#,刷题,c++,动态规划求解)