使用置换和组合遍历N * N矩阵的方式数量

时间:2019-04-03 09:56:32

标签: algorithm matrix combinations permutation dynamic-programming

这个想法是从N * N矩阵的左上角移动到右下角,其中唯一允许的移动是向下或向右移动。不允许回溯。使用动态编程很简单,如以下geeks for geeks链接所示。我试图了解如何使用简单的排列和组合来实现相同的目的。我遇到了以下BetterExplained链接。他们要解决的问题肯定不匹配。有没有一种方法可以使用排列和组合找到解决方案?可以帮助我更好地了解解决方案的指针吗?

编辑1:

以下是 3X3 矩阵的示例,当我们进行动态编程时,它显示了从左上点到右下点的6种方式,仅当使用公式{ {1}}。但是我列出了20种从起点到目的地的到达方式,即2(N-1)!/ (N-1)!(N-1)!,或者我对这个问题的理解有误,这是可行的,因为我们已经在最左上角的单元格中,并遍历到最右下角的单元格单元格,那么答案将是2N!/N!*N!

enter image description here

3 个答案:

答案 0 :(得分:2)

(n-1) among 2(n-1)种方法可以使用您给出的规则遍历n*n矩阵。

一个简单的解释:由于仅允许移动downwardrightward,因此路径的长度必须恰好为2(n-1)
更重要的是,在这条路径中,将有n-1个移动downward,还有n-1个移动rightward(这是从路径到达右下角的唯一可能方式左上角)。
因此,(n-1) among 2(n-1)来自所有可能的方式来适应n-1的移动,并在2(n-1)的移动中向下执行。

答案 1 :(得分:1)

如果矩阵是正方形(N x N),我相信可以按以下方式计算路径数,其中n = N - 1

from math import factorial

def number_of_paths(n):
    return int(factorial(2 * n) / (factorial(n) ** 2))

至于为什么...那有点复杂。首先,不要考虑上下左右移动,而是将矩阵旋转45度,以便我们始终向下移动,但是选择向左还是向右。

我们的矩阵现在是位于其末端的菱形,并形成Pascal's triangle的中心。这意味着我们可以查看Pascal三角形底行中心处的binomial coefficient,它是矩阵尺寸的两倍-1。

我们使用二项式系数,因为对此的一种解释是它显示了我们可以选择到达那里的路径数。

例如,在3 x 3情况下,2 * 3 - 1 = 5

       [1]                          C(0,0)
     [1   1]                    C(1,0), C(1,1)
   [1   2   1]              C(2,0), C(2,1), C(2,2)
  1  [3   3]   1        C(3,0), C(3,1), C(3,1), C(3,1)
1   4 [!6!]  4   1  C(4,0), C(4,1), C(4,2), C(4,3), C(4,4)

   Answer is 6!              Answer is C(4, 2)!

答案是(2n)! / n! ** 2(以下推导),我们可以直接计算出它。

您还可以通过在关心的底行中移动项目来将其推广为非平方矩阵,此时,您基本上只得到C(n, k)。希望很清楚为什么。

只是数学!

从上图可以看到N的前三个值是:

N | Value
- + -------
1 | C(0, 0)
2 | C(2, 1)
3 | C(4, 2)

因此我们可以看到答案是:

= C(2(N - 1), N - 1)

let n = N-1
Given C(a, b) = a! / b!(a - b)!

= C(2n, n)
= (2n)! / n!(2n - n)!
= (2n)! / n! ** 2

路径长度的几何解释

想象一下4x4矩阵的情况,尝试看看为什么长度为2(N-1)。首先是一些观察结果:

  • 所有路径长度相同
  • 因此,我们可以考虑采用任何特定的路径来检查所有长度
  • 因此,请考虑以下路径:
    • 从左上到右上(全部向右)
    • 然后从右上到右下(全部向下)

首先,我们从左上方开始,没有任何动作,然后沿着顶部进行:

0 - - -     0 1 - -     0 1 2 -     0 1 2 3
- - - -  >  - - - -  >  - - - -  >  - - - -  
- - - -     - - - -     - - - -     - - - - 
- - - -     - - - -     - - - -     - - - -

经过3步移动后,我们遍历了长度4侧。因此,对于长度为N的一面,需要N-1来移动。垂直方向也是如此,这将需要我们再执行另一N-1个移动才能从顶部到底部遍历:

0 1 2 3     0 1 2 3     0 1 2 3     0 1 2 3
- - - -  >  - - - 4  >  - - - 4  >  - - - 4  
- - - -     - - - -     - - - 5     - - - 5 
- - - -     - - - -     - - - -     - - - 6

因此,总路径长度为2(N-1)

答案 2 :(得分:0)

使用组合函数从am * n网格的左上角移动到右下角的总数为(n-1 + m-1)!/(n-1)!(m-1)!

#include <iostream> 
using namespace std; 

int numberOfPaths(int m, int n) 
{ 
// We have to calculate m+n-2 C n-1 here 
// which will be (m+n-2)! / (n-1)! (m-1)! 
int path = 1; 
for (int i = n; i < (m + n - 1); i++) { 
    path *= i; 
    path /= (i - n + 1); 
} 
return path; 
} 
int main() 
{ 
cout << numberOfPaths(3, 3); 
return 0; 
} 

输出:6