计算从左上到右下的所有可能路径

时间:2019-03-20 21:01:18

标签: java dynamic-programming

任务是计算mXn矩阵从左上角到右下角的所有可能路径,并限制每个单元只能向右或向下移动。

     int[][] count = new int[n][m];
     int i,j;

     for (i = 0; i < n; i++)
         count[i][0] = 1;
     for (i = 0; i < m; i++)
         count[0][i] = 1;

     for (i = 1; i < n; i++)
         for (j = 1; j < m; j++)
             count[i][j] = (count[i - 1][j] + count[i][j - 1]);

     System.out.println(count[n - 1][m - 1]);

上面的代码显示了对于较大的m和n值的错误答案。 使用长数组也不起作用。 在一种正确的解决方案中,公式 `count [i] [j] =(count [i-1] [j] + count [i] [j-1])%((int)Math.pow(10,9)+7)< / strong>; 用来! 我不明白为什么会这样。

2 个答案:

答案 0 :(得分:0)

使用正方形进行测试并使用int,您最多可以计算17x17。如果使用18x18,则会出现数字溢出。

要检测数字溢出,请更改以下行:

count[i][j] = (count[i - 1][j] + count[i][j - 1]);

收件人:

count[i][j] = Math.addExact(count[i - 1][j], count[i][j - 1]);

以18x18运行时,您会得到java.lang.ArithmeticException: integer overflow,而17x17会显示601080390

更改为long会将限制提高到34x34 = 7219428434016265740,而35x35会失败。

要超出此范围,请使用BigInteger

private static void count(int n, int m) {
    BigInteger[][] count = new BigInteger[n][m];
    for (int i = 0; i < n; i++)
        count[i][0] = BigInteger.ONE;
    for (int i = 0; i < m; i++)
        count[0][i] = BigInteger.ONE;
    for (int i = 1; i < n; i++)
        for (int j = 1; j < m; j++)
            count[i][j] = count[i - 1][j].add(count[i][j - 1]);
    System.out.println(n + "x" + m + ": " + count[n - 1][m - 1]);
}

您现在可以计算出非常大的尺寸:

public static void main(String[] args) {
    for (int i = 10; i < 150; i+=10)
        count(i,i);
}

输出

10x10: 48620
20x20: 35345263800
30x30: 30067266499541040
40x40: 27217014869199032015600
50x50: 25477612258980856902730428600
60x60: 24356699707654619143838606602026720
70x70: 23623985175715118288974865541854103729000
80x80: 23156006494021191956342707682359261381151378400
90x90: 22880174247360071687155809670095748237789263482394000
100x100: 22750883079422934966181954039568885395604168260154104734000
110x110: 22738029575969641265497648088901902565550598643635116137437818400
120x120: 22820983692956015651850538861400483591556161461874723704379950728024000
130x130: 22985198722890636106807214387141205118592781510195606858610359655612113472140
140x140: 23220197341838572012462842682887166477737842005968501197039194284526789533662125200

答案 1 :(得分:0)

从m x n网格的左上角到右下角仅需向右和向下移动m + n-2个步骤:m-向右1个步骤,向下n-1个步骤。每条不同的路径的特征在于对这些步骤中哪些向下的特定选择(等效地:这些步骤中的哪个正确)。有一个解析解决方案:

factorial(m + n - 2) / (factorial(m - 1) * factorial(n - 1))

您可能会意识到,它是m + n-2阶的第m-1个 二项式系数。

当然,您不需要用这种方式进行计算,实际上,如果需要这样做,则需要格外小心,因为阶乘会快速增长。这就是我提出它的原因:无论用什么方式进行计算,结果都会在m接近n的情况下快速增长,很快就超过了long的范围-尽管是指数级的,而不是阶乘的。

  

在一种正确的解决方案中,公式`count [i] [j] =(count [i-1] [j] + count [i] [j-1])%((int)Math.pow (10,9)+7);用来!我不明白为什么会这样。

无法正确解决您所提出的问题,但是我看到了该问题的修改版本,在该版本中很有意义:一个要求您计算结果的版本 取模1000000007 ,这正是让您感到困惑的事情。我想我已经在欧拉计画上看到过,但也可能在其他地方。这种问题上的变化使人们可以完全避免在具有32位整数类型的任何系统上出现无法表示的整数的问题。