暴力递归转动态规划(十二)

题目
给定5个参数,N,M,row,col,k。
表示在 N * M的区域上,醉汉Bob初始在(row,col)位置。Bob一共要迈出k步,且每步都会等概率向上下左右四个方向走一个单位。
任何时候Bob只要离开N * M的区域,就直接死亡
求:返回k步之后,Bob还在N*M的区域的概率。

暴力递归
根据题意确定base case:
如果Bob走出 N * M 范围就狗带,所以无论四个方向里走哪个方向,都要在 N * M的范围内。
根据给定范围N * M确定Bob走动范围是0 ~ N - 1, 0 ~ M -1 。所以row < 0 || row = N || col < 0 || col = M。
如果K步走完,则return 1。

代码
总方法数:一共走K步,每一步都有4个方向可以选择,所以总方法数是 4k ,用在N * M内的方法数 / 总方法数,就是所得概率。

public static double livePosibility1(int row, int col, int k, int N, int M) {
        return (double) (process(row, col, k, N, M)) / Math.pow(k, 4);
    }

    public static int process(int row, int col, int rest, int N, int M) {
    	//走出N * M范围,直接狗带
        if (row < 0 || row == N || col < 0 || col == M) {
            return 0;
        }
		
		//还在范围内,不过剩余步数rest = 0,此时return 1.
        if (rest == 0) {
            return 1;
        }
        int left = process(row - 1, col, rest - 1, N, M);
        int right = process(row + 1, col, rest - 1, N, M);
        int up = process(row, col + 1, rest - 1, N, M);
        int down = process(row, col - 1, rest - 1, N, M);

        return left + right + up + down;
    }

动态规划
根据暴力递归代码更改动态规划,可变参数为row,col和剩余步数rest。所以是一个三维dp表。
根据代码中的依赖关系可以看出,每一步都是依赖rest - 1,所以层级的上下依赖,同层级之间是没有依赖关系的。
所以先填充rest层,剩余的row和col,从前往后,从后往前填充效果一样。

代码
根据base case,当rest = 0时 return 1,所以第一个遍历是填充默认值。
第二层遍历中的pick方法是防止数组下标越界。

public static double dp(int row, int col, int k, int N, int M) {
        int[][][] dp = new int[N][M][k + 1];
		
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                dp[i][j][0] = 1;
            }
        }
        for (int rest = 1; rest <= k; rest++) {
            for (int r = N - 1; r >= 0; r--) {
                for (int c = M - 1; c >= 0; c--) {
                    dp[r][c][rest] = pick(dp, r - 1, c, rest - 1, N, M);
                    dp[r][c][rest] += pick(dp, r + 1, c, rest - 1, N, M);
                    dp[r][c][rest] += pick(dp, r, c + 1, rest - 1, N, M);
                    dp[r][c][rest] += pick(dp, r, c - 1, rest - 1, N, M);
                }
            }
        }
        return (double)dp[row][col][k] / Math.pow(4,k);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值