如何使用递归来使用简单数组

时间:2015-11-20 20:09:48

标签: c recursion dynamic-programming backtracking

我是编码的初学者。我想使用简单的递归和数组来解决以下问题。但我无法将其可视化。我想出了使用链接列表的解决方案。以下是问题和我的解决方法

  

给定n行整数,使得第i行(1 <= i <= n)   包含我的整数。使用以下一组路径规则,找到   具有最大重量的路径。

     

路径遍历规则:

     
      
  1. 有效路径序列将自上而下,即以第一行中的整数开头,并遍历所有行,只选择一行   每行中的整数。

  2.   
  3. 从第i行中的任何第j个整数,即row[i][j],遍历可以向下(即row[i+1][j])或斜向下发生   向右(即row[i+1][j+1])。

  4.         

    Path的权重是Path中整数值的总和   序列。

         

    示例:

        No. of Rows: 5 
            4 
            2    9 
            15   1    3 
            16   92  41  44 
            8   142  6    4    8 
    
         

    预期输出:4,2,15,92,142(最大重量为255)

Sol.c

#include<stdio.h>
#include<stdlib.h>

int n,**ar;

struct n
{
 int i,j;
 int w;
 struct n *ptr;
};

struct n* maxweight(int i,int j,struct n* x)
{
 struct n* tmp=malloc(sizeof(struct n)),*t1,*t2;
 tmp->i=i;
 tmp->j=j;
 tmp->ptr=x;
 tmp->w=ar[i][j];
 if(x)tmp->w+=x->w;
 if(i==n-1)return tmp;
 t1=maxweight(i+1,j,tmp);
 t2=maxweight(i+1,j+1,tmp);
 if(t1->w>t2->w)return t1;
 return t2;
}

int main()
{
 int i,j;
 struct n * s;
 printf("Enter the value of n\n");
 scanf("%d",&n);
 ar=malloc(n*sizeof(int*));
 for(i=0;i<n;i++)
 {
  ar[i]=malloc((i+1)*sizeof(int));
  for(j=0;j<=i;j++)scanf("%d",&ar[i][j]);
 }
 s=maxweight(0,0,NULL);
 printf("MAX WEIGHT is :%d\nPATH: ",s->w);
 while(s)
 {
  printf("%d ",ar[s->i][s->j]);
  s=s->ptr;
 }
 printf("\n");
 return 0;
}

如何在没有使用n x n矩阵的链接列表的情况下使用递归来解决这个问题?动态编程是否适用于此问题。

1 个答案:

答案 0 :(得分:2)

专注于计算你的前方路径的权重; 不要回头。

首先解决一个简单的边缘情况。假设你做到了最底行。然后没有什么可以追随的;剩下的路径重量为零。

在代码中:

int getWeight(int i, int j)
{
    int remaining = 0;

在任何其他行中,您必须做出选择。你应该左转还是右转?由于目前无法知道哪一个最好,你只需要尝试两个方向:

    if (i < lastRow)
    {
        int weightLeft  = getWeight(i + 1, j);
        int weightRight = getWeight(i + 1, j + 1);

注意我递归地调用了我自己的函数; 盲目信仰,该功能能够为剩余路径提供最佳权重!

尝试了两个方向后,选择最重要的重量:

        int best_j = weightLeft > weightRight ? j : j + 1;

现在我们再次走上选定的道路。

        remaining = getWeight(i + 1, best_j);
    }

这不是很有效,但它有助于收集最佳路径的各个步骤。我将使用一个简单的数组pathColumns

    pathColumns[i] = j;

最后,我们需要对这些值求和。

    return row[i][j] + remaining;
}

要设置整个运动,只需调用该函数,并将顶部单元格的坐标传递给它。出于实际原因,我将所有数组都设为base-0。所以顶部单元格是row[0][0]

printf("Optimal weight: %d\n", getWeight(0, 0));

全部放在一起:

#include <stdio.h>

#define n 5

int pathColumns[n] = {0};

int row[n][n] =
{
    {4},
    {2, 9},
    {15, 1, 3},
    {16, 92, 41, 44},
    {8, 142, 6, 4, 8}
};

int getWeight(int i, int j)
{
    int remaining = 0;
    if (i < n-1)    /* with base-0, the last row is n-1 */
    {
        int weightLeft  = getWeight(i + 1, j);
        int weightRight = getWeight(i + 1, j + 1);
        int best_j = weightLeft > weightRight ? j : j + 1;
        remaining = getWeight(i + 1, best_j);
    }
    pathColumns[i] = j;
    return row[i][j] + remaining;
}

int main()
{
    int i;
    printf("Optimal weight: %d\n", getWeight(0, 0));
    for (i = 0; i < n; i++)
    {
        int j = pathColumns[i];
        printf("(%d, %d) = %d\n", i+1, j+1, row[i][j]);
        /* NOTE: +1 is a correction to bring the output back to base-1 */
    }
    return 0;
}

输出:

Optimal weight: 255
(1, 1) = 4
(2, 1) = 2
(3, 1) = 15
(4, 2) = 92
(5, 2) = 142

如何运作

我们希望getWeight(0, 0)返回此金字塔最重的路径。

          4  <---- (0, 0) is our starting point
         / \
        2   9
      /  \ /  \
    15    1    3
    / \  / \  / \
  16   92   41   44
 /  \ /  \ /  \ /  \
8   142   6    4    8

递归算法进行两次递归调用。

  • getWeight(1, 0)必须获得我们起点下方和左侧的子金字塔最重的路径。
  • getWeight(1, 1)必须获得我们起点下方和右侧的次金字塔最重的路径。

两个次金字塔:

        2  <--- (1, 0)         9  <--- (1, 1)
      /  \                    /  \
    15    1                  1    3
    / \  / \                / \  / \
  16   92   41            92   41   44
 /  \ /  \ /  \          /  \ /  \ /  \
8   142   6    4      142    6    4    8

假设getWeight(1, 0)getWeight(1, 1)返回正确的权重(分别为251和244),剩下要做的就是选择最高权重(251)并添加大金字塔的最高值对它(4)。结果是255。

我们所做的是减少一个问题(计算高度为5的金字塔的最大权重),这样我们就可以解决两个较小的问题(计算高度为4的金字塔的最大权重)。以同样的方式,我们可以减少高度4的问题来解决高度3的相同问题。例如,getWeight(1, 1)将进行两次递归调用getWeight(2, 1)getWeight(2, 2)

       1  <--- (2, 1)      3  <--- (2, 2)
      / \                 / \
    92   41             41   44
   /  \ /  \           /  \ /  \
142    6    4         6    4    8

getWeight(1, 1)应返回244 = 9 + max(235,55)。

继续这样,我们最终最终解决了高度为1的金字塔的问题。这些是原始金字塔底部的值(8,142,6,4和8)。这里的递归结束了;高度为1的金字塔只不过是一个节点。该节点的值是通过该金字塔的(唯一)路径的权重。