POJ 1163 The Triangle(动态规划入门题)

题目链接

The Triangle
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 54525 Accepted: 32875

Description

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

(Figure 1)
Figure 1 shows a number triangle. 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. The following N lines describe the data of the triangle. The number of rows in the triangle is > 1 but <= 100. The numbers in the triangle, all integers, are between 0 and 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


解题思路:

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

D( r, j) : 第r行第 j 个数字(r,j从1开始算)

MaxSum(r, j) : 从D(r,j)到底边的各条路径中,最佳路径的数字之和。

问题:求 MaxSum(1,1)

典型的递归问题。
D(r, j)出发,下一步只能走D(r+1,j)或者D(r+1, j+1)。故对于N行的三角形:

if ( r == N)

MaxSum(r,j) = D(r,j)
else

MaxSum( r, j) = Max{ MaxSum(r+1,j), MaxSum(r+1,j+1) }+ D(r,j)

但因重复计算,时间复杂度为(2的n次方)用递归肯定超时。所以采用改进的递归算法,将没算出来的MaxSum(r,j)保存起来,下次用到其值的时候直接取用,则可避免重复计算。此时的时间复杂度为(n的平方)。

数字三角形的记忆递归型动态规划程序:

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX],N;
int maxsum[MAX][MAX];

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
		maxsum[i][j] = max(Maxsum(i+1,j),Maxsum(i+1,j+1)) + D[i][j];
	return maxsum[i][j];
}

int main(){
	int i,j;
	scanf("%d",&N);
	for(i = 1; i <= N; i++)
		for(j = 1; j <= i; j++){
			scanf("%d",&D[i][j]);
			maxsum[i][j] = -1;
		}
	
	printf("%d\n",Maxsum(1,1));
	return 0;
}

将“递归”转变成“递推”:

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int maxSum[MAX][MAX];
int main(){
	int i,j,N;
	scanf("%d",&N);
	for(i = 1; i <= N; i++)
		for(j = 1; j <= i; j++){
			scanf("%d",&D[i][j]);
		}
	for(i = 1; i <= N; i++)
		maxSum[N][i] = D[N][i];
	for(i = N-1; i >= 1; i--)
		for(j = 1; j <= i; j++){
			maxSum[i][j] = max(maxSum[i+1][j],maxSum[i+1][j+1]) + D[i][j]; 
		}							        //此处的加不能用maxSum[i][j] 
	printf("%d\n",maxSum[1][1]);					//因为maxSum只有最后一行赋值
	return 0;							        // 了,其它都是随机的 
 } 

空间优化:

    没必要用二维maxSum数组存储每一个MaxSum(r,j),只要从底层一行行向上递推,那么只要一维数组maxSum[100]即可,即只要存储一行的MaxSum值就可以。

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int maxSum[MAX];
int main(){
	int i,j,N;
	scanf("%d",&N);
	for(i = 1; i <= N; i++)
		for(j = 1; j <= i; j++){
			scanf("%d",&D[i][j]);
		}
	for(i = 1; i <= N; i++)
		maxSum[i] = D[N][i];
	for(i = N-1; i >= 1; i--)
		for(j = 1; j <= i; j++){
			maxSum[j] = max(maxSum[j],maxSum[j+1]) + D[i][j]; 
		}											 
	printf("%d\n",maxSum[1]);					
	return 0;										
 } 

继续空间优化:

    进一步考虑,连maxSum数组都可以不要,直接用D的第n行替代maxSum即可。

    节省空间,时间复杂度不变。

#include<iostream>
#include<algorithm>
using namespace std;
#define MAX 101
int D[MAX][MAX];
int * maxSum;
int main(){
	int i,j,N;
	scanf("%d",&N);
	for(i = 1; i <= N; i++)
		for(j = 1; j <= i; j++){
			scanf("%d",&D[i][j]);
		}
	maxSum = D[N];  //maxSum指向第n行 
	for(i = N-1; i >= 1; i--)
		for(j = 1; j <= i; j++){
			maxSum[j] = max(maxSum[j],maxSum[j+1]) + D[i][j]; 
		}											 
	printf("%d\n",maxSum[1]);					
	return 0;										
 } 
此动态规划题为学习过程中,老师给的例题。在此作一下总结,记录,方便以后的进一步学习。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值