赞
踩
问题:
给定一个由n行数字组成的数字三角形,如下图所示:
试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大(每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数)。
输入格式:
第一行是数字三角形的行数,接下来 n 行是数字三角形中的数字。
输出格式:
最大总和(整数)
样例输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出
30
此解法的思想是从a[0][0]开始递归,len(a[i]][j]) = max(len(a[i+1][j]), len(a[i+1][j+1])) + a[i][j],递归到最底层之后开始对递归返回。
对于n层的数字三角形,该解法的时间复杂度为2*(1+2+4+8+16+….+2^(n-1)),因而为O(2*2^n-1)约等于O(2^n)
#include<iostream>
#define MAX 101
using namespace std;
int a[MAX][MAX];
int n;
int max_sum(int i, int j)
{
int max1, max2;
if(i == (n-1)) return a[i][j];
max1 = max_sum(i+1, j);
max2 = max_sum(i+1, j+1);
if(max1>max2)
{
return max1+a[i][j];
}
else
{
return max2+a[i][j];
}
}
int main()
{
int i = 0, j = 0;
cin>>n;
for(i = 0; i<n; i++)
{
for(j = 0; j<=i; j++)
{
cin >> a[i][j];
}
}
cout << max_sum(0, 0)<<endl;
return 0;
}
此解法的思想是再开辟一块内存来代替递归时的记忆过程,时间开销基本不变,加上空间消耗,总体性能不如解法一。
#include<iostream>
#define MAX 101
using namespace std;
int a[MAX][MAX];
int n;
int maxnum[MAX][MAX];
int max(int a, int b)
{
return a>b ? a : b;
}
int max_sum(int i, int j)
{
int max1, max2;
if(i == (n-1))
{
maxnum[i][j] = a[i][j];
}
if(maxnum[i][j] != -1)
{
return maxnum[i][j];
}
max1 = max_sum(i+1, j);
max2 = max_sum(i+1, j+1);
maxnum[i][j] = max(max1, max2) + a[i][j];
return maxnum[i][j];
}
int main()
{
int i = 0, j = 0;
cin>>n;
for(i = 0; i<n; i++)
{
for(j = 0; j<=i; j++)
{
cin >> a[i][j];
maxnum[i][j] = -1;
}
}
cout << max_sum(0, 0)<<endl;
PrintArr();
return 0;
}
与解法二相比,这种解法以递推取代递归,避免了进栈出栈的时间开销。对于有n层的数字三角形,时间复杂度为O(n^2/2),约等于O(n^2)。
#include<iostream>
#define MAX 101
using namespace std;
int a[MAX][MAX];
int maxsum[MAX][MAX];
int n;
int max(int a, int b)
{
return (a>b ? a : b);
}
int max_sum(void)
{
int i = 0;
int j = 0;
int max1, max2;
for(i = n-1; i>=0; i--)
{
for(j = 0; j<=i; j++)
{
if(i == (n-1))
{
maxsum[i][j] = a[i][j];
continue;
}
max1 = maxsum[i+1][j];
max2 = maxsum[i+1][j+1];
maxsum[i][j] = max(max1, max2) + a[i][j];
}
}
return maxsum[0][0];
}
int main()
{
int i = 0, j = 0;
cin>>n;
for(i = 0; i<n; i++)
{
for(j = 0; j<=i; j++)
{
cin >> a[i][j];
maxsum[i][j] = -1;
}
}
cout << max_sum()<<endl;
return 0;
}
解法四是对解法三的一种优化,在开辟辅助空间时不再开辟一个n*n的二维数组,而是采用长度为n的一维数组。因为对数字三角形的计算结果是自底向上的,对每一层的结果在上一层利用完之后就没用了,并且每一层的大小从低往上是递减的,因此可以开辟最下层大小的空间来保存每一层的计算结果。当然,时间复杂度仍为解法三的时间复杂度。
#include<iostream>
#define MAX 101
using namespace std;
int a[MAX][MAX];
int maxsum[MAX];
int n;
int max(int a, int b)
{
return (a>b ? a : b);
}
int max_sum(void)
{
int i = 0, j = 0;
int max1, max2;
for(i = n-1; i>=0; i--)
{
for(j = 0; j<=i; j++)
{
if(i == (n-1))
{
maxsum[j] = a[i][j];
continue;
}
max1 = maxsum[j];
max2 = maxsum[j+1];
maxsum[j] = max(max1, max2) + a[i][j];
}
}
return maxsum[0];
}
int main(){
int i = 0, j = 0;
cin>>n;
for(i = 0; i<n; i++)
{
for(j = 0; j<=i; j++)
{
cin >> a[i][j];
maxsum[i] = -1;
}
}
cout << max_sum()<<endl;
return 0;
}
在完成解法四的时候我们发现:既然每一层的结果在用完之后该层就没用了,那么我们完全没有必要开辟额外的辅助空间–利用二维数组a本身最下层的空间就好了。
#include<iostream>
#define MAX 101
using namespace std;
int a[MAX][MAX];
int n;
int max(int a, int b)
{
return (a>b ? a : b);
}
int max_sum(void)
{
int i = 0, j = 0;
int max1 = 0, max2 = 0;
for(i = (n-2); i>=0; i--)
{
for(j = 0; j<=i; j++)
{
max1 = a[i+1][j];
max2 = a[i+1][j+1];
a[i][j] += max(max1, max2);
}
}
return a[0][0];
}
int main()
{
int i = 0, j = 0;
cin>>n;
for(i = 0; i<n; i++)
{
for(j = 0; j<=i; j++)
{
cin >> a[i][j];
}
}
cout << max_sum()<<endl;
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。