Java 冗余路径的记忆

Java 冗余路径的记忆,java,dynamic-programming,memoization,Java,Dynamic Programming,Memoization,我正在解决一个问题,其中有一个包含r行和c列的网格。我们从左上角单元格开始,到右下角单元格结束。限制是我们一次只能移动一个单元格,向下或向右移动。此外,一些单元格可能被列入黑名单。问题是找到我们从源头到目标的总途径 这是我的解决方案,它简单明了,但以指数时间运行: int count(boolean[][] array, int r, int c) { if ((r < 0 || c < 0) || !array[r][c]) return 0; if (r == 0

我正在解决一个问题,其中有一个包含r行和c列的网格。我们从左上角单元格开始,到右下角单元格结束。限制是我们一次只能移动一个单元格,向下或向右移动。此外,一些单元格可能被列入黑名单。问题是找到我们从源头到目标的总途径

这是我的解决方案,它简单明了,但以指数时间运行:

int count(boolean[][] array, int r, int c)
{
    if ((r < 0 || c < 0) || !array[r][c]) return 0;
    if (r == 0 && c == 0) return 1;
    return count(array, r - 1, c) + count(array, r, c - 1);
}
int计数(布尔[][]数组,int r,int c)
{
if((r<0 | | c<0)| |!数组[r][c])返回0;
如果(r==0&&c==0)返回1;
返回计数(数组,r-1,c)+计数(数组,r,c-1);
}
我遇到的问题是在回忆这件事的时候

  • 记忆化能使这个解决方案更有效吗
  • 如果是这样的话,那么我就不能将失败路径中的所有单元都列入黑名单,因为可能有其他路径通过这些单元,从而导致目标。所以我很困惑,我应该在这里缓存什么,在哪里添加额外的检查以避免检查我已经通过的路径
  • 如果(1)是肯定的,那么如果没有细胞被列入黑名单,那么我想知道备忘录是否会起到任何作用
  • 记忆化能使这个解决方案更有效吗

    对!

    如果是这样的话,那么我就不能将失败路径中的所有单元都列入黑名单,因为可能有其他路径通过这些单元,从而导致目标

    所以我很困惑,我应该在这里缓存什么,在哪里添加额外的检查以避免检查我已经通过的路径

    这是你要做的

    制作一个由可空整数组成的rxc2-d数组,我们称之为
    a
    。数组的含义是“
    a[x][y]
    给出从(x,y)到(r-1,c-1)的路径数”——这是假设(r-1,c-1)是我们试图到达的“出口”单元

    数组将以每个元素为空开始。太好了。Null表示“我不知道”

    在数组中的每个“阻塞”单元格中填入零。这意味着“没有办法从这个牢房到出口”

    如果
    a[r-1][c-1]
    为零,那么出口被阻塞,我们就完成了。每个查询的答案都是零,因为无法到达出口。假设退出单元没有被阻塞

    有一种方法可以从出口单元格到它自己,所以用1填写
    a[r-1][c-1]

    现在,算法是这样进行的:

    20 10  4  1
    10  6  3  1
     4  3  2  1
     1  1  1  1
    
    • 我们需要从单元格
      (x,y)
      开始的解决方案
    • 查阅数组。如果为空,则在右下邻域递归,并用这些答案的总和填充
      [x][y]
      处的数组
    • 现在数组肯定已填充,因此返回
      a[x][y]
    让我们举个例子。假设我们有

    n  n  n
    n  n  0
    n  n  1
    
    我们需要(0,1)的解。我们没有解决办法。所以我们试图找到(1,1)和(0,2)的解

    我们没有(1,1)的解决方案。所以我们必须得到(1,2)和(2,1)的解

    (1,2)我们有。是0

    我们没有,但我们有,那是唯一的邻居。(2,2)是1,所以我们填写(2,1):

    现在我们有足够的信息来填写(1,1):

    我们还没有完成(0,2)。它有一个邻居是零,所以:

    n  n  0
    n  1  0
    n  1  1
    
    现在我们可以填写(0,1)

    这就是我们一直在寻找的,所以我们完成了

    替代解决方案:预计算阵列

    • 我们开始填写所有的0和出口处的1,就像以前一样
    • 现在从下往上填充最右边的一列:它是全1,直到你到达第一个零,在这一点上它变成全0
    • 现在从右向左填写最下面一行。同样,它是全1,直到你到达第一个零,在这一点上它变成全0
    • 现在我们有足够的信息来填写右栏的第二个和底行的第二个;你看到了吗
    • 继续这样操作,直到填充完整个数组
    • 现在所有答案都在数组中
    例如:

    第一步:

    n  n  n
    n  n  0
    n  n  1
    
    填写外部行和列:

    n  n  0
    n  n  0
    1  1  1
    
    n  1  0
    2  1  0
    1  1  1
    
    填写下一行和下一列:

    n  n  0
    n  n  0
    1  1  1
    
    n  1  0
    2  1  0
    1  1  1
    
    最后一点:

    3  1  0
    2  1  0
    1  1  1
    
    我们完成了;整个问题都解决了

    如果没有被列入黑名单的细胞,那么我想知道备忘录是否会有任何作用

    如果没有被列入黑名单的单元格,则数组如下所示:

    20 10  4  1
    10  6  3  1
     4  3  2  1
     1  1  1  1
    
    这是一个你以前应该见过的形状,并且知道如何直接计算每个元素。提示:您通常将其视为三角形,而不是正方形

    记忆化能使这个解决方案更有效吗

    对!

    如果是这样的话,那么我就不能将失败路径中的所有单元都列入黑名单,因为可能有其他路径通过这些单元,从而导致目标

    所以我很困惑,我应该在这里缓存什么,在哪里添加额外的检查以避免检查我已经通过的路径

    这是你要做的

    制作一个由可空整数组成的rxc2-d数组,我们称之为
    a
    。数组的含义是“
    a[x][y]
    给出从(x,y)到(r-1,c-1)的路径数”——这是假设(r-1,c-1)是我们试图到达的“出口”单元

    数组将以每个元素为空开始。太好了。Null表示“我不知道”

    在数组中的每个“阻塞”单元格中填入零。这意味着“没有办法从这个牢房到出口”

    如果
    a[r-1][c-1]
    为零,那么出口被阻塞,我们就完成了。每个查询的答案都是零,因为无法到达出口。假设退出单元没有被阻塞

    有一种方法可以从出口牢房出来