递推之数字三角形

题目描述:

在如下的数字三角形中寻找一个从顶部到底部的路径,对于任意一个点(最后一行除外),每一步只可以向下或者向右下走,找一条经过的数字之和最大的路径,求出这个和。

输入:

5 //代表有5行

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

输出:

30


首先考虑三角形的存储,毫无意外,首先选择二维数组,但是这是一个下三角矩阵,一个 n 阶的下三角矩阵将会浪费 n*n-n*(n+1)/2 的空间,因此我们选择将它存在一维数组中,对于一个 5 行的下三角矩阵,只需要 n*(n+1)/2 的一维数组就可以了。

for(int i = 0; i<n; i++)   // n 阶
    {
        j = 0;
        while(i>=j)
        {
            b[k++] = a[i][j];
            j++;
        }
    }

接下来是编写求最大和的算法,首先考虑一个特殊情况,假设我们有一个 3 阶的下三角矩阵,而且元素都是按升幂排列:

1

2 3

4 5 6

我们很容易找到一个算法来描述它,即从顶部开始,判断哪一个最大,然后定义一个变量,让最大的数加给它。由于是在一维数组中,我们只需要找到每一行开始的下标和行号的关系,

第一行第一个     1*(1-0)/2

第二行第一个     2*(2-1)/2

第三行第一个     3*(3-1)/2

....

接下来我们考虑另外一种情况:

1

2 3

8 4 3

如果按照刚才的方法,我们会得到结果 1+3+4 = 8,可显然最大的应该是 11,这就是思维的一个误区,我们不能一开始就盲目的找"看起来"最大的数字。

这样我们换个思路,从下往上走,对于处在上一层的下方和右下位置的数字总要选其一,然后将大的加给上面它对应的那个数字,也就是先判断 4 和 3,将 4 加给 第二层的 3,再判断 8 和 4 ,8 加给第二层的 2,此时一维数组中是这样的

1 10 7 8 4 3

继续,就得到最大的数 11 了。

#include <iostream>

using namespace std;

int sum = 0;

int Judge(int b[],int i,int j)
{
    if(b[i]>b[j])
        return i;
    return j;
}

int Sum(int b[],int n)
{
    int k = n,i = n*(n+1)/2-1,y = 1;
    sum = b[0];
    while(i >0 && k >1)
    {
        int j = Judge(b,i-1,i);
        int x = k*(k-1)/2-y++;
        b[x] += b[j];
        if(x == (k-1)*(k-2)/2){
        k--;
        y = 1;
        i--;
        }
        i--;
    }
    return b[0];
}

int main()
{
    int n,j = 0,k = 0;
    cin >> n;
    int b[n*(n+1)/2],a[n][n];
    for(int i = 0; i<n; i++)
    {
        for(int j = 0; j<=i; j++)
            cin>>a[i][j];
    }
    for(int i = 0; i<n; i++)
    {
        j = 0;
        while(i>=j)
        {
            b[k++] = a[i][j];
            j++;
        }
    }
    cout<<Sum(b,n);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/eliminatedacmer/article/details/79438395