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)
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;
}
此动态规划题为学习过程中,老师给的例题。在此作一下总结,记录,方便以后的进一步学习。