【USACO】numtri

给一颗数字树,让找一条数字和最大的路径。一下子就想起刚学不久的回溯法了。照着写了个代码,调了调搞通了。在小数据的情况下是对的,但是在test 6 树有199层的时候溢出了。

#include <stdio.h>

int BackTrack(int n, int (*num)[1000], int * summax) //回溯法

{

    *summax = 0;

    int sum = 0;

    int k = 0;

    int S[1000] = {0};

    int sign[1000] = {0};

    int sumn[1000] = {0};  //保存算到第k行的和

    S[k] = 1;

    sign[k] = 0;

    do{

        while(S[k] != 0)

        {

            if(S[k] == 1 && k != 0)

            {

                sign[k]++; //选择右边的数

            }

            if(k == 0)

            {

                sumn[k] = num[k][sign[k]];

            }

            else

            {

                sumn[k] = sumn[k - 1] + num[k][sign[k]];

            }

            S[k]--;

            if(k < n - 1)

            {

                k++;

                S[k] = 2; //新到一行时 共有两个选择

                sign[k] = sign[k - 1] + 2 - S[k];  //选择左边的数

            }

            else

            {

                if(sumn[k] > *summax)

                {

                    *summax = sumn[k];

                }



            }

        }

        k--;

    }while(k > 0);

    return 0;

}



int main()

{

    FILE *in, *out;

    in = fopen("numtri.in", "r");

    out = fopen("numtri.out", "w");



    int N;

    int num[1000][1000];

    int summax;

    int i, j;

    fscanf(in, "%d", &N);

    for(i = 0; i < N; i++)

    {

        for(j = 0; j <= i; j++)

        {

            fscanf(in, "%d", &num[i][j]);

        }

    }



    BackTrack(N, num, &summax);

    fprintf(out, "%d\n", summax);



    return 0;

}

 -------------------------------------------------------------

针对回溯法溢出,很容易想到的是计算有冗余。举例来说: 在计算5的分支时,其实下面7的情况已经在之前都算过了的,只要知道7 和 8哪个数对应的下面的和最大就好了。

3

4 5

6 7 8

9 10 11 12

于是可以换成从下到上的解法,从最底下开始计算在每一层对应位置上和最大的数,最下面一层就是数本身,再往上每次都是 数本身 + max(下一行左边最大求和数, 下一行右边最大求和数), 在最高层时输出最大值。写完代码后很奇怪,自己的电脑上跑总是溢出,但在测评系统上却AC了。

#include <stdio.h>



int max(int a, int b)

{

    return a > b ? a : b;

}



int tmp[1000] = {0}; //每层用同一个tmp存储最大值就好了,因为在计算出高层的最大值后,低层的最大值就没有用了。

int downtotop(int c, int N, int (*num)[1000])

{

    int i;

    if(c == N)

    {

        if(c != 1)

        {

            for(i = 0; i < c; i++)

            {

                tmp[i] = num[c - 1][i];

            }

            downtotop(c-1, N, num);

        }

        else //针对只有一个数的情况

        {

            return num[0][0];

        }

    }

    else

    {

        for(i = 0; i < c; i++)

        {

            tmp[i] = num[c - 1][i] + max(tmp[i], tmp[i + 1]);

        }

        if(c == 1)

        {

            return tmp[0];

        }

        else

        {

            downtotop(c-1, N, num);

        }

    }

}



int main()

{

    FILE *in, *out;

    in = fopen("numtri.in", "r");

    out = fopen("numtri.out", "w");



    int N;

    int num[1000][1000];

    int summax;

    int i, j;

    fscanf(in, "%d", &N);

    for(i = 0; i < N; i++)

    {

        for(j = 0; j <= i; j++)

        {

            fscanf(in, "%d", &num[i][j]);

        }

    }



    summax = downtotop(N, N, num);

    fprintf(out, "%d\n", summax);



    return 0;

}

 -------------------------------------------

经过好友点拨,发现是int num[1000][1000]太大了,超过了栈内存,必须动态分配。改好后自己在电脑上也跑通了。在测评系统上消耗的内存也小了。

    int i;

    int N;

    fscanf(in, "%d", &N);



    int **num = (int **)malloc(1000 * sizeof(int *));

    for(i = 0; i < N; i++)

    {

        num[i] = (int *)malloc(1000 * sizeof(int));

    }

 --------------------------------------

看了答案还是想复杂了 不需要递归的 直接for循环就好

 for (i = 0; i < rows; i++)

    res[i] = tri[rows-1][i];



  for (i = rows-1; i > 0; i--)

    for (j = 0; j <= i; j++)

      res[j] = tri[i-1][j] + max(res[j],res[j+1]);

 -----------------------------------

答案还有一种从上到下的思路,不用先把数字存下来,可以取一个计算一步。如同从上到下,每次有两个选择,从下到上每次也是两个选择(边上的只有一个选择),从上往下加时可以只选择两个上方已有数字钟最大的,最后可以得到最下方N个最大值,选出其中最大的一个即可。

    for(i=1; i<=r; i++) {

        memmove(oldbest, best, sizeof oldbest);

        for(j=0; j<i; j++) {

            fscanf(fin, "%d", &n);

            if(j == 0)

                best[j] = oldbest[j] + n;

            else

                best[j] = max(oldbest[j], oldbest[j-1]) + n;

        }

    }

 

你可能感兴趣的:(USACO)