冗余路径的记忆

时间:2018-03-21 19:59:53

标签: 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 && c == 0) return 1;
    return count(array, r - 1, c) + count(array, r, c - 1);
}

我遇到的问题是记住这个问题。

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

1 个答案:

答案 0 :(得分:3)

  

记忆能否使这个解决方案更有效率?

是!

  

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

正确。

  

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

这是你做的。

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

数组将从每个元素null开始。那很棒。 Null的意思是“我不知道”。

用零填充数组中的每个“被阻止”单元格。这意味着“没有办法从这个单元格到达出口”。

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

有一种方法可以从退出单元格到达自身,因此请将a[r-1][ c-1]填入1。

现在算法继续这样:

  • 我们被要求从单元格(x, y)开始的解决方案。
  • 咨询阵列。如果它为null,则递归右侧和右侧邻居,并使用这些答案的 sum 填写[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,1)我们没有但是(2,2)我们这样做,那是唯一的邻居。 (2,2)是1,所以我们填写(2,1):

n  n  n
n  n  0
n  1  1

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

n  n  n
n  1  0
n  1  1

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

n  n  0
n  1  0
n  1  1

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

n  1  0
n  1  0
n  1  1

我们正在寻找的是什么,所以我们已经完成了。

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

  • 我们首先填写所有零和出口处的一个零点。
  • 现在填写从下到上的最右边的列:它是全部的,直到你到达第一个零点,此时它变为全零。
  • 现在从右到左填写最下面的一行。同样,它是全部的,直到你到达第一个零点,此时它变为全零。
  • 现在我们有足够的信息来填充右起第二列和第二行第二行;你怎么看?
  • 继续这样做,直到填满整个阵列。
  • 现在所有的答案都在数组中。

示例:

第一步:

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

最后一次:

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

这是您之前应该看到的形状,并且知道如何直接计算每个元素。提示:你通常把它看成是一个三角形而不是正方形。