数字三角形

问题描述:有一个由非负整数组成的三角形,第一行有一个数,除了最下行以外每个数的左下方和右下方各有个数,如下所示:
数字三角形_第1张图片
问题:从第一行的数开始,每次可以往左下或右下走一格,直到走到最下行,把沿途经过的数字加起来,如何才能使得这个和尽量大?

分析:首先,规定状态,如下:
数字三角形_第2张图片
这道题是典型的动态决策问题,每次有两种选择,左下或者右下。
首先,定义问题的状态:将当前的位置(i,j)看成一个状态,定义d(i,j)是从(i,j)出发能获得的最大值和(包括(i,j)本身的值),在这个状态定义下,原问题的解就是d(1,1)。
再看状态转移过程:从格子(i,j)出发有两种决策。如果往左下走,则走到(i+1,j)需要求出“ 从(i+1,j)出发的最大和”这一子问题,即要求出d(i,j)必须求出子问题d(i+1,j)和d(i+1,j+1),从中选择较大的一个。
可写状态转移方程:d(i,j) = a(i,j) + max{d(i+1,j),d(i+1,j+1)}
(其中a(i,j) 是格子编号(i,j)值)
解法1:(从上往下直接递归法)
代码片段如下:

int DP_MaxPathSum(int i,int j)
{
	if(i == n)
	return a[i][j];  // 基础解,到最后一行则返回自身的值
	return d[i+1][j+1] > d[i+1][j] ? d[i+1][j+1] :d[i+1][j];
}

这样做会重复计算子问题,效率低下。如下所示:
数字三角形_第3张图片
阴影部分会被计算多次。时间复杂度是O(2^n)。

解法2:(自底向上)

int DP_MaxPathSum()
{
	int i,j;
	for(i = 1;i<= n;i++)
	d[n][i] = a[n][i];//基础解
	for(i = n-1;i>0;i--)
		for(j = 1;j<=i;j++){
			d[i][j] = d[i+1][j] > d[i+1][j+1] ? d[i+1][j] : d[i+1][j+1];
		}
		return d[1][1];
}

自底向上,计算d(i,j) 时其子问题d(i+1,j)和d(i+1,j+1)已经计算出来,其时间复杂度是O(n^2)。

解法3:(自顶向下带备忘)
首先使用memset(d,-1,sizeof(d))对d全部初始化为-1。

int max(int i,int j)
{
	return i > j?i:j;
}
int DP_MaxPathSum(int i,int j)
{
	if(d[i][j] >= 0)
		return d[i][j]; //直接返回重叠子问题
	if(i == n) {
		d[i][j] = a[i][j];
		return d[i][j]; //基础解
	}
	d[i][j] = a[i][j] + max(DP_MaxPathSum(i+1,j+1),DP_MaxPathSum(i+1,j));
	return d[i][j];
}

时间复杂度是O(n^2)。

输入是数字三角形,输出是最大和。

样例输入:1 3 2 4 10 1 4 3 2 20
样例输出:24

使用语言:C++,使用方法3,完整代码如下:

//数字三角形
#include 
#include 
#include 
using namespace std;

int arr[10000][10000]; //存放输入
int dp[10000][10000];
int n;
int max(int value1,int value2)
{
	return value1>value2?value1:value2;
}

int dp_maxpathsum(int x,int y) 
{
	if(dp[x][y] != 0)
		return dp[x][y];
	if(x == 4)
		return arr[x][y];
	else
	dp[x][y] = max(dp_maxpathsum(x+1,y),dp_maxpathsum(x+1,y+1))+arr[x][y];
	return dp[x][y];
}
int main()
{
	int value;
	memset(arr,0,sizeof(arr));
	memset(dp,0,sizeof(dp));
	//输入数据
	vector vec;
	while(cin >> value)
		vec.push_back(value);
	while((n*(n+1)/2) != vec.size())
		n++;
	int index = 0;
	for(int i = 1;i<=n;i++)
		for(int j = 1;j<=i;j++)
			arr[i][j] = vec[index++];

	cout <

你可能感兴趣的:(动态规划)