The Triangle

题目限制

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 59262 Accepted: 35557
时间限制: 1000ms 内存限制: 10000k
提交:59262 接受:35557

Description

描述

			    7
		   	  3   8
			8   1   0
		  2   7   4   4
		4   5   2   6   5

(Figure 1)
Figure 1 shows a number triangle.
图1显示了一个数字三角形。
Write a program that calculates the highest sum of numbers passed on a route that starts at the top and ends somewhere on the base.
编写一个程序,计算从顶部开始,在底部某个位置结束的路由上传递的最大数字总和。
Each step can go either diagonally down to the left or diagonally down to the right.
每一步都可以向左斜向下或向右斜向下。

Input

输入
Your program is to read from standard input.
您的程序将从标准输入中读取。
The first line contains one integer N: the number of rows in the triangle.
第一行包含一个整数n:三角形中的行数。
The following N lines describe the data of the triangle.
下面的n行描述了三角形的数据。
The number of rows in the triangle is > 1 but <= 100.
三角形中的行数大于1但小于等于100。
The numbers in the triangle, all integers, are between 0 and 99.
三角形中的数字,所有整数,都在0到99之间。

Output

输出
Your program is to write to standard output.
您的程序将写入标准输出。
The highest sum is written as an integer.
最高的和被写为一个整数。

Sample Input

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

Sample Output

30
Source
IOI 1994

解题思路

用二维数组存放数字三角形

D(i,j):第i行第j个数字(r,j从1开始算)
MaxSum(r,j):从D(i,j)到底边的各条路径,最佳路径的数字之和。

问题:求MaxSum(1,1)

典型的递归问题:
D(i,j)出发,下一步只能走到D(i+1,j)或者D(i+1,j+1)。

递归代码

#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;
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(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			cin>>D[i][j];
		}
	}
	cout<<MaxSum(1,1)<<endl;
	return 0;
}

想都不用想,肯定会:Time Limit Exceeded

为什么会超时?

重复计算:
如果采用递归的方法,深度遍历每条路径,存在大量重复计算,时间复杂度为2n

改进

如果每算出一个MaxSum()就保存起来,下次用到其值的时候直接取用,则可免去重复计算。
因为三角形的数字总数是n(n+1)/2,那么可以用O(n2)时间完成计算。

记忆递归型动态规划程序

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

递归转递推

从下往上,每两个数往上找一层最大数:
在这里插入图片描述

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

空间优化

直接用D的最后一行存放maxSum

#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX],n;
int * maxSum;
int main ()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			cin>>D[i][j];
		}
	}
	maxSum=D[n];
	for(int i=n-1;i>=1;i--)
	{
		for(int j=1;j<=i;j++)
		{
			maxSum[j]=max(maxSum[j],maxSum[j+1])+D[i][j];
		}
	}
	cout<<maxSum[1]<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/AlexKing007/p/12339439.html