计算带有障碍物的网格中的路径和我的分析

时间:2016-12-30 02:55:06

标签: java algorithm path-finding

我想制作一个程序,可以获得从左上到右下方的路径总数,并且会有一些障碍。

例如,如果我有如下的网格迷宫:

@ + + + +
+ + + X X
+ X + + +
+ + + X +
+ X + + X
+ + + + $

它应该告诉我从@到$有9条路径(只能向右或向下移动)。 因此我首先为网格制作了一个没有任何障碍的小程序,这里是代码:

import java.util.*;
import java.math.*;

public class s15 {
    private static long nChooseK(int k, int n) {
        BigInteger numerator = p(k,n);
        BigInteger denominator = p2(k); 
        return numerator.divide(denominator).longValue();
    }

    private static BigInteger p2(int k) {
        BigInteger r = BigInteger.valueOf(1);
        while (k != 0) {
            BigInteger k1 = BigInteger.valueOf(k);
            r = r.multiply(k1);

            k--;
        }
        return r;
    }


    private static BigInteger p(int k, int n) {
        int p;
        int s = 1;
        BigInteger r = BigInteger.valueOf(s);
        for (int i = 0; i <= k-1; i++ ) {
            p = n - i;
            BigInteger p1 = BigInteger.valueOf(p);
            r = r.multiply(p1);
        }
        return r;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        int y = sc.nextInt();

        System.out.println(nChooseK(x, x+y));
    }



}

然后我首先尝试使用此代码来获取没有任何障碍的迷宫有多少路径5*6。然后我得到462,但是我必须考虑障碍因此我减去462,每个障碍的路径到$,我得到数字:21 70 6 15 10 3,令人惊讶的是,在我使用462-21-70-6-15-10-3之后,我得到一个数字是比9大得多,我想如果我使用没有障碍物的总路径来阻挡总路径障碍物,它应该是有障碍物的总路径。什么地方出了错? THX!

3 个答案:

答案 0 :(得分:2)

阻挡的总路径障碍并不容易计算。它应该是从@开始,向下或向右移动,以$结尾并至少传递一个障碍的路径数。

对于这个问题,有两种算法针对不同的数据规模。

1)Inclusion–exclusion principle

阻挡的总路径障碍物=(通过任何一个障碍物的总路径) - (通过任意两个障碍物的总路径)+(通过任何三个障碍物的总路径) - ...

通过任何K障碍物的总路径只能使用枚举计算。也就是说,将整个障碍的所有子集与K个元素精确对齐,并计算通过它们的路径。

考虑到K个障碍,如果有任何两个障碍形成(左,下) - (右,上)对,则没有路径可以通过这些障碍物。 否则,我们可以从(左,上)到(右,下)对它们进行排序,计数将是(从@到障碍物1的总路径)*(从障碍物1到障碍物2的总路径)* ... * (从障碍物K到$的总路径。)

最后,从a到b的总路径可以通过nChooseK来解决。多长的日记!

假设存在S个障碍,该算法的时间复杂度为O(S * 2 ^ S)。

2)Dynamic Programming

如果您已经知道DP,这会容易得多。如果没有,我会建议你谷歌并先学习它。

简而言之,公式是

f[0][0] = 1
if cell (i, j) is an obstacle
  f[i][j] = 0 
else
  f[0][j] = f[0][j - 1]
  f[i][0] = f[i - 1][0]
  f[i][j] = f[i - 1][j] + f[i][j - 1]
Answer = f[N - 1][M - 1]

其中f [i] [j]表示从@开始的总路径,不传递障碍物并在单元格(i,j)处结束,而(N,M)是电路板的尺寸。

时间复杂度为O(NM)。

答案 1 :(得分:1)

dp[i][j]=dp[i-1][j] + dp[i][j-1]...if g[i-1][j] and g[i][j-1] is free.
The points neighbor to start point will be of length 1( ofc valid points)

好的,那个贬低的人......谢谢他。

所以这里要记住3件事

  1. 我们只能向下或向右移动。因此,如果他们完全自由,我们可以从两点来看[i,j]点。那些将是[i-1,j]或[i,j-1]。

  2. reacj [i,j]的路径数等于达到[i-1,j]和[i,j-1](如果空闲)的方式之和。

  3. 我们需要考虑一些边缘情况,如[0,y]或[x,0]。

  4. 所以

       dp[i][j]=  dp[i-1][j]+dp[i][j-1] if i>=1 & j>=1
                  dp[i][j-1]            if i=0  & j>=1
                  dp[i-1][j]            if i>=1 & j =0
                  1                     if i=0  & j =0
                  0                     if x[i][j] is obstacle
    

    答案为dp[row-1][col-1]

    Time complexity: O(row*col)
    Space complexity: O( row*col)
    

    dp数组将是

    1 1 1 1 1 
    1 2 3 0 0 
    1 0 3 3 3
    1 1 4 0 3
    1 0 4 4 0
    1 1 5 9 9
    

答案 2 :(得分:0)

作为参考,如果障碍物很少,除了上面的“包含-排除”方法之外,还可以按距起点的距离对障碍物进行排序,以便所有障碍物都不会包含在任何先前的障碍物中。现在,考虑我们可以将通过某障碍物的每条路径划分为它经过的第一个障碍物。然后,我们可以为每个障碍物计算以该障碍物为第一个障碍物的路径。一旦我们知道了,只需对它们进行总结就可以得到答案。

时间复杂度:O(k ^ 2),其中k为障碍物数量