将动态编程集成到递归解决方案中

问题描述

我正在尝试将动态编程应用于以下问题:

一个机器人位于mxn网格的左上角。该机器人只能在任何时间点向下或向右移动。该机器人正试图到达网格的右下角。有唯一的路径吗?”

我对此有一个递归解决方案,我认为效果很好。但是,它很慢:

int uniquePaths(int m,int n)
    {
        if (m==1 || n==1)
        {
           return 1;
        }
        else 
        {
            return (uniquePaths(m,n-1)+uniquePaths(m-1,n));
        }
    }

我可以看到,如果我们能够保存uniquePath调用输出,这将很有用,因为许多操作将多次执行。我对如何实现此目标的一个想法是创建一个m x n数组,然后将输出存储在那里。但是,这意味着我需要将数组输入到我的递归函数中,并且我认为对于这个问题,我只允许输入两个整数。有一种简单的方法可以应用此方法吗?

解决方法

您不需要将数组作为函数参数输入。它可以是局部变量。

天真的方式:使用递归函数

如果您真的想使用递归函数,可以在uniquePaths中声明数组,然后调用另一个将使用该数组并进行计算的函数。

int uniquePaths_helper(int *grid,int m,int n,int i,int j);

int uniquePaths(int m,int n)
{
    int *grid = malloc(m * n * sizeof(int));
    int k;
    for (k = 0; k < m * n; ++k)
    {
        grid[k] = 0;
    }
    return uniquePaths_helper(grid,m,n);
}

int uniquePaths_helper(int *grid,int j)
{
    if (grid[i * m + j] == 0)
    {
        if (i == n - 1 || j == n - 1)
        {
           grid[i * m + j] = 1;
        }
        else 
        {
            grid[i * m + j] = (
                uniquePaths_helper(grid,n,i+1,j)
                + uniquePaths_helper(grid,i,j+1)
            );
        }
    }
    return grid[i * m + j];
}

变得更聪明:以正确的顺序填充数组

在先前的解决方案中,存在很多开销,因为我们必须使用默认值初始化数组,然后在每个递归调用中,我们都需要检查值是否已经存储在数组中或是否需要计算。 / p>

您可以简化所有操作。使用您的公式在grid的单元格上直接填充数组,而不是在递归调用的参数上填充数组。

公式为:grid[i * m + j] == grid[(i+1) * m + j] + grid[i * m + j+1]

唯一棘手的部分是找出填充数组的顺序,以便可以将该公式写为简单的赋值,用==替换=

由于单元格中的值仅取决于具有更高的ij索引的值,因此我们可以简单地向后填充数组:

int uniquePaths(int m,int n)
{
    int *grid = malloc(m * n * sizeof(int));
    int i,j;

    for (int i = 0; i < n; ++i)
        grid[i * m + m-1] = 1;
    for (int j = 0; j < m; ++j)
        grid[(n-1) * m + j] = 1;

    for (i = n - 2; i >= 0; --i)
    {
        for (j = m - 2; j >= 0; --j)
        {
            grid[i * m + j] = grid[(i+1) * m + j] + grid[i * m + j+1];
        }
    }
    return grid[0];
}