动态规划三维练习之象棋问题

问题描述

给你一个棋盘,长为10,宽为9,然后在棋盘的[0,0]位置,有一个马,马走日嘛,就是象棋的规则,现在在棋盘上给你一个位置[a,b],给你k步,请你求出,马走到【a,b】位置并且走k步,可以有多少种走法?

暴力递归

先说一下总体思路,马走k步从【0,0】位置走到【a,b】,其实和从ab走到0是不是一样啊?因此,思路中虽然是0到ab,但是在代码中,写ab到0比较容易一些。
递归出口base case
当马走出棋盘时,说明失败了,返回0。
当k步走完时,如果a=0且b=0,说明找到一种,返回1,否则返回0。
递归函数
当base case不成立时,就向周围八个方向走日,然后将结果加起来返回。
代码

    public static int f1(int x,int y,int k){
        if(x<0||x>8||y<0||y>9){
            return 0;
        }
        if(k==0){
            return (x==0&&y==0)? 1:0;
        }
        int res=f1(x+1,y+2,k-1);
        res+=f1(x+1,y-2,k-1);
        res+=f1(x+2,y+1,k-1);
        res+=f1(x+2,y-1,k-1);
        res+=f1(x-1,y+2,k-1);
        res+=f1(x-1,y-2,k-1);
        res+=f1(x-2,y+1,k-1);
        res+=f1(x-2,y-1,k-1);
        return res;
    }

三维动态规划

因为此题的递归解法中,有三个可变参数,因此,画图的结果是三维图,也就是立方体。三维的动态规划,其实本质上和二维是一样的。

    public static int dpWays(int x,int y,int k){
        //排除掉特殊情况
        if(x<0||x>8||y<0||y>9||k<0){
            return 0;
        }
        //创建三维表格
        int[][][] dp=new int[9][10][k+1];
        //根据递归出口写出第一层的结果,只有【000】位置是1,其余都是0,数组默认值是0,所以不用写了
        dp[0][0][0]=1;
        //h从1开始,因为第一层已经已知结果了
        for (int h = 1; h <=k; h++) {
            //i、j都之和上一层有关,因此,ij的顺序无所谓
            for (int i = 0; i < x; i++) {
                for (int j = 0; j < y; j++) {
                    //根据递归函数得出:上面一层的dp结果是由下一层的八个位置相加得出的
                    dp[i][j][h]+=getValue(dp,i-1,j+2,h-1);
                    dp[i][j][h]+=getValue(dp,i-1,j-2,h-1);
                    dp[i][j][h]+=getValue(dp,i+1,j+2,h-1);
                    dp[i][j][h]+=getValue(dp,i+1,j-2,h-1);
                    dp[i][j][h]+=getValue(dp,i+2,j+1,h-1);
                    dp[i][j][h]+=getValue(dp,i+2,j-1,h-1);
                    dp[i][j][h]+=getValue(dp,i-2,j+1,h-1);
                    dp[i][j][h]+=getValue(dp,i-2,j-1,h-1);
                }
            }
        }
        return dp[x][y][k];
    }

    //处理越界问题
    private static int getValue(int[][][] dp, int x, int y, int k) {
        if(x<0||x>8||y<0||y>9||k<0){
            return 0;
        }
        return dp[x][y][k];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值