蘑菇阵(动态规划、百度)——unique paths

题目描述

现在有两个好友A和B,住在一片长有蘑菇的由n*m个方格组成的草地,A在(1,1),B在(n,m)。现在A想要拜访B,由于她只想去B的家,所以每次她只会走(i,j+1)或(i+1,j)这样的路线,在草地上有k个蘑菇种在格子里(多个蘑菇可能在同一方格),问:A如果每一步随机选择的话(若她在边界上,则只有一种选择),那么她不碰到蘑菇走到B的家的概率是多少?

输入描述:
第一行N,M,K(2 ≤ N,M ≤ 20, k ≤ 100),N,M为草地大小,接下来K行,每行两个整数x,y,代表(x,y)处有一个蘑菇。

输出描述:
输出一行,代表所求概率(保留到2位小数)

输入例子:
2 2 1
2 1

输出例子:
0.50
解题思路:
题目要求的是不碰到蘑菇的概率,一开始我使用路径数的方法来求解的(p=不碰到蘑菇的走法/所有的走法),但是一直都未能通过所有测试。后来认真研究了下题目,也看了些网上的一些资料。题目要求要计算不碰到蘑菇的概率,因为走的概率不均等,如
2 3的蘑菇阵
1 2 3
4 5 6
从1 走到6
1-2的概率为0.5,2-3概率为0.5,3-6概率为1
1-4的概率为0.5,2-5概率为0.5,4-5概率为1,5-6概率为1,3-6概率为1
若走1-2-3-6概率为0.25,1-2-5-6概率为0.25,而走1-4-5-6的概率为0.5
所以三种走法的概率不均等,所以算其不碰到蘑菇的概率不可以用枚举路径数的方法计算。只能往两个方向走,所以两个方向的概率都是0.5,但是在边界处只有一种走法也就是该走法的概率为1,需要单独对边界进行处理。
不是边界的计算不碰到蘑菇的概率:
ways[i][j] = ways[i-1][j] * 0.5 * (map[i-1][j] + 1)%2+ ways[i][j-1] * 0.5 (map[i-1][j] + 1)%2 即为上面和左边的方向过来,前提上面和左边都没有蘑菇
边界的处理:
最底端第n行:ways[i][j] = ways[i][j-1] * (map[i-1][j] + 1)%2
最右边第m列:ways[i][j] = ways[i-1][j] * (map[i-1][j] + 1)%2

public static double getProbability(int map[][], int n, int m) {
        double ways[][] = new double[n][m];// 没走蘑菇阵的概率
        ways[0][0] = 1;

        // int ti = 0, tj = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {//注意处理单行和单列的问题
                if (j == m - 1 && i - 1 >= 0) {// 最右边
                        ways[i][j] += ways[i - 1][j];   
                }
                if (i == n - 1 && j -1 >=0) {// 最下边
                    ways[i][j] += ways[i][j - 1];
                }
                if(i - 1 >= 0)//不止一行
                    if (map[i - 1][j] != 1 && j != m - 1) {// 往下走的概率
                        ways[i][j] += ways[i - 1][j] * 0.5;
                    }
                if (j-1 >= 0) {//不止一列
                    if (map[i][j - 1] != 1 && i != n - 1) {// 往右边走
                        ways[i][j] += ways[i][j - 1] * 0.5;
                    }
                }

                if (map[i][j] == 1) {//如果终点是蘑菇则概率为0
                    ways[i][j] = 0;
                }

            }

        }

        if (map[n - 1][m - 1] == 1) {
            ways[n - 1][m - 1] = 0;
        }

//      show(ways, n, m);
        return ways[n - 1][m - 1];

    }

一开始我用路径求解的方法,该路径数方法也是一个动态规划的方法但不适合于蘑菇阵这个题目,将该方法稍微改改就是LeetCode里的两道动态规划题目unique paths和unique paths II

/**
     * 用路径法求解概率=可以走的路径/总的路径,算了好久都是错的,因为走的路径概率不一样( ╯□╰ )
     * 
     * @param map
     * @param n
     * @param m
     * @return
     */
    public static double getPathNumProbability(int map[][], int n, int m) {
        int ways[][][] = new int[n][m][3];// 0存储没有走蘑菇的,1存储走蘑菇的,2存储没考虑蘑菇的
        ways[0][0][1] = 0;
        ways[0][0][0] = 1;
        ways[0][0][2] = 1;
        for (int i = 1; i < n; i++) {// 首列
            ways[i][0][2] = 1;
            ways[i][0][0] = ways[i - 1][0][0];
            ways[i][0][1] = ways[i - 1][0][1];
            if (map[i - 1][0] == 1) {
                ways[i][0][1] = 1;
                ways[i][0][0] = 0;
            }
        }
        for (int j = 1; j < m; j++) {// 首行
            ways[0][j][0] = ways[0][j - 1][0];
            ways[0][j][1] = ways[0][j - 1][1];
            ways[0][j][2] = 1;
            if (map[0][j - 1] == 1) {
                ways[0][j][1] = 1;
                ways[0][j][0] = 0;
            }

        }
        // int ti = 0, tj = 0;
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < m; j++) {
                ways[i][j][2] = ways[i - 1][j][2];// 往下走
                if (map[i - 1][j] == 1) {
                    ways[i][j][1] = ways[i - 1][j][2];
                    ways[i][j][0] = 0;
                } else {
                    ways[i][j][1] = ways[i - 1][j][1];
                    ways[i][j][0] = ways[i - 1][j][0];
                }

                ways[i][j][2] += ways[i][j - 1][2];// 往右走
                if (map[i][j - 1] == 1) {
                    ways[i][j][1] += ways[i][j - 1][2];
                    ways[i][j][0] += 0;
                } else {
                    ways[i][j][0] += ways[i][j - 1][0];
                    ways[i][j][1] += ways[i][j - 1][1];
                }
            }

        }
        if (map[n - 1][m - 1] == 1) {

            ways[n - 1][m - 1][0] = 0;
        }
        // System.out.println("ways[n-1][m-1][2] "+ways[n-1][m-1][2]+" 00
        // "+ways[n-1][m-1][0]+" 11 "+ways[n-1][m-1][1]);
        // show(ways,n,m);
        return ways[n - 1][m - 1][0] * 1.0 / ways[n - 1][m - 1][2];

    }

leetcode unique paths

/**
     * 
     * leetcode unique paths
     * A robot is located at the top-left corner of a m x n grid (marked 'Start'
     * in the diagram below).
     * 
     * The robot can only move either down or right at any point in time. The
     * robot is trying to reach the bottom-right corner of the grid (marked
     * 'Finish' in the diagram below).
     * 
     * How many possible unique paths are there?
     * 
     * 
     * Above is a 3 x 7 grid. How many possible unique paths are there?
     * 
     * @param m
     * @param n
     * @return
     */
    public int uniquePaths(int m, int n) {
        int map[][] = new int[m][n];
        int ways[][] = new int[n][m];//
        ways[0][0] = 1;
        for (int i = 1; i < n; i++) {// 首列
            ways[i][0] = 1;
        }
        for (int j = 1; j < m; j++) {// 首行
            ways[0][j] = 1;
        }
        // int ti = 0, tj = 0;
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < m; j++) {
                ways[i][j] = ways[i - 1][j];// 往下走
                ways[i][j] += ways[i][j - 1];// 往右走
            }
        }
        return ways[n - 1][m - 1];
    }

稍微改改就是leetcode Unique Paths II 的解


 * leetcode Unique Paths II Follow up for "Unique Paths":
 * 
 * Now consider if some obstacles are added to the grids. How many unique
 * paths would there be?
 * 
 * An obstacle and empty space is marked as 1 and 0 respectively in the
 * grid.
 * 
 * For example, There is one obstacle in the middle of a 3x3 grid as
 * illustrated below.
 * 
 * [ [0,0,0], [0,1,0], [0,0,0] ] The total number of unique paths is 2.
 * 
 * @param map
 * @param n
 * @param m
 * @return
 */
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    int n = obstacleGrid.length, m = obstacleGrid[0].length;
    int ways[][][] = new int[n][m][3];// 0存储没有走障碍的,1存储走障碍的,2存储没考虑障碍的
    ways[0][0][1] = 0;
    ways[0][0][0] = 1;
    ways[0][0][2] = 1;
    for (int i = 1; i < n; i++) {// 首列
        ways[i][0][2] = 1;
        ways[i][0][0] = ways[i - 1][0][0];
        ways[i][0][1] = ways[i - 1][0][1];
        if (obstacleGrid[i - 1][0] == 1) {
            ways[i][0][1] = 1;
            ways[i][0][0] = 0;
        }

    }
    for (int j = 1; j < m; j++) {// 首行
        ways[0][j][0] = ways[0][j - 1][0];
        ways[0][j][1] = ways[0][j - 1][1];
        ways[0][j][2] = 1;
        if (obstacleGrid[0][j - 1] == 1) {
            ways[0][j][1] = 1;
            ways[0][j][0] = 0;
        }

    }
    // int ti = 0, tj = 0;
    for (int i = 1; i < n; i++) {
        for (int j = 1; j < m; j++) {
            ways[i][j][2] = ways[i - 1][j][2];// 往下走
            if (obstacleGrid[i - 1][j] == 1) {
                ways[i][j][1] = ways[i - 1][j][2];
                ways[i][j][0] = 0;
            } else {
                ways[i][j][1] = ways[i - 1][j][1];
                ways[i][j][0] = ways[i - 1][j][0];
            }

            ways[i][j][2] += ways[i][j - 1][2];// 往右走
            if (obstacleGrid[i][j - 1] == 1) {
                ways[i][j][1] += ways[i][j - 1][2];
                ways[i][j][0] += 0;
            } else {
                ways[i][j][0] += ways[i][j - 1][0];
                ways[i][j][1] += ways[i][j - 1][1];
            }
        }

    }
    if (obstacleGrid[n - 1][m - 1] == 1) {

        ways[n - 1][m - 1][0] = 0;
    }
    // System.out.println("ways[n-1][m-1][2] "+ways[n-1][m-1][2]+" 00
    // "+ways[n-1][m-1][0]+" 11 "+ways[n-1][m-1][1]);
    // show(ways,n,m);
    return ways[n - 1][m - 1][0];
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值