一尘不染

如何计算受±1或±2步幅约束的简单路径?

algorithm

我发现了这个有趣的动态编程问题,并且想知道这种方法。

给我们一个大小为’n’的数组’a’。

数组的每个元素都是“ 1”或“ 2”。

我们从索引‘0’开始。如果a [i] = 1,我们可以转到i + 1或i-1。

相反,如果a [i] = 2,我们可以转到i + 1或i + 2或i-1或i-2。

我们必须找到所有可能路径的数量。

主要约束:-1)我们只能访问一次数组中的特定索引。

2)我们总是从索引‘0’开始。

3)一条路径可以在我们想要的任何时候结束:-)

数组示例:-> [1,1,1,1]

回答:-4

第一条可能路径:[0]

第2条可能的路径:[0,1]

第三种可能的路径:[0,1,2]

第四条可能的路径:[0,1,2,3]

另一个例子 : -

[2,2,2]

答案:-5

路径:-[0],[0,1],[0,1,2],[0,2,1],[0,2]

(此问题分为3部分!)

n的值在范围内:-1)[1,100000]

                            2) [1,10]

                             3)[1,1000]

阅读 211

收藏
2020-07-28

共1个答案

一尘不染

考虑使用的空间。

0 1 2 3 4 5 6
      ^

为了从右边获得一个数字,必须使用它之前的单元格。因此,所有以x左边结尾的方式都不能包含右边的数字。而所有方法的最终结果x都来自使用x-1的右侧,以及x从左侧向右侧不相交的一组移动。

f(A, x) = l(A, x) + r(A, x),其中l(A, x)表示从左侧开始以x结尾的所有方式;r(A, x),来自右边。

要获取l(A, x),我们需要:

(1) all ways to reach (x-1)
    = l(A, x-1)

  (there are no numbers used to
   the right of x, and since
   x is used last, we could not
   have reached x-1 from the right.)

(2) all ways to reach (x-2):
    cleary we need l(A, x-2). Now
    to reach (x-2) from the right,
    the only valid path would have
    been ...(x-3)->(x-1)->(x-2)
    which equals the number of ways
    to reach (x-3) from the left.

    = l(A, x-2) + l(A, x-3)

要获取r(A, x),我们需要:

(1) all ways to reach (x+1) so as
    to directly go from there to x
    = l(A, x-1)

  (We can only reach (x+1) from (x-1).)

(2) all ways to reach (x+2) after
    starting at (x+1)
    = l(A, x-1) * f(A[x+1...], 1)

  (To get to the starting point in
   A[x+1...], we must first get to
   (x-1).)

所以看来

f(A, x) = l(A, x) + r(A, x)

  l(A, x) =
    l(A, x-1) + l(A, x-2) + l(A, x-3)

  r(A, x) =
    l(A, x-1) + l(A, x-1) * f(A[x+1...], 1)

每次我们运行以下JavaScript代码时,它都会尝试使用不同的7元素数组。我将备忘录和优化留给读者(为了有效地制表f(_, 1),请注意l(_, 1) = 1)。

function f(A, x){

  if (x < 0 || x > A.length - 1)

    return 0



  return l(A, x) + r(A, x)



  function l(A, x){

    if (x < 0 || x > A.length - 1)

      return 0

    if (x == 0)

      return 1



    let result = l(A, x-1)



    if (A[x-2] && A[x-2] == 2){

      result += l(A, x-2)



      if (A[x-3] && A[x-3] == 2)

        result += l(A, x-3)

    }



    return result

  }



  function r(A, x){

    if (x < 0 || x >= A.length - 1 || !(A[x-1] && A[x-1] == 2))

      return 0



    let result = l(A, x-1)



    if (A[x+2] && A[x+2] == 2)

      result += l(A, x-1) * f(A.slice(x+1), 1)



    return result

  }

}





function validate(A){

  let n = A.length



  function g(i, s){

    if (debug)

      console.log(s)

    let result = 1

    let [a, b] = [i+1, i-1]



    if (a < n && !s.includes(a))

      result += g(a, s.slice().concat(a))

    if (b >= 0 && !s.includes(b))

      result += g(b, s.slice().concat(b))



    if (A[i] == 2){

      [a, b] = [i+2, i-2]



      if (a < n && !s.includes(a))

        result += g(a, s.slice().concat(a))

      if (b >= 0 && !s.includes(b))

        result += g(b, s.slice().concat(b))

    }



    return result

  }



  return g(0, [0])

}



let debug = false



let arr = []

let n = 7

for (let i=0; i<n; i++)

  arr[i] = Math.ceil(Math.random() * 2)

console.log(JSON.stringify(arr))

console.log('')



let res = 0

for (let x=0; x<arr.length; x++){

  let c = f(arr,  x)

  if (debug)

    console.log([x, c])

  res += c

}



if (debug)

  console.log('')

let v = validate(arr)

if (debug)

  console.log('')

console.log(v)

console.log(res)
2020-07-28