zoukankan      html  css  js  c++  java
  • [Leetcode]688.Knight Probability in Chessboard

    链接:LeetCode688

    已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始。即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1)。 
    现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动。 
    如下图所示,国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置。
    现在 “马” 每一步都从可选的位置(包括棋盘外部的)中独立随机地选择一个进行移动,直到移动了 K 次或跳到了棋盘外面。
    求移动结束后,“马” 仍留在棋盘上的概率。

    相关标签:动态规划

    这并不是一道常规的动态规划题。但是如果想到动态规划来解,其转移方程也是不难想的。
    首先创建一个三维数组(dp[i][j][k]),其中(dp[i][j][k])表示棋盘位置为(i)(j)列的旗子经过(k)步后在棋盘上的概率。每一步,棋子共有八种走法,创建一个二维数组,保存这八个走法,每次循环这八步。对于某个点的八个走法中的任意一个,将该点的位置加上八个走法中的值,得到另外一个位置,用1/8 乘于另外位置上一步得到的棋子位于棋盘上的概率。

    至于为什么是(dp[i][j][k])呢?为什么我们要将走的步数放在最外面,这也不难想。我们走k步的状态是由走了k-1步时的状态得到的,所以我们想得到在位置((i,j))上概率,肯定需要走了k-1步时的概率,所以要将k放在最外层进行遍历。

    其代码如下:

    python:

    class Solution:
        def knightProbability(self, N: int, K: int, r: int, c: int) -> float:
            dp = [[[0 for _ in range(K+1)] for _ in range(N)] for _ in range(N)]
            for k in range(K+1):
                for i in range(N):
                    for j in range(N):
                        if k==0:
                            dp[i][j][k] = 1
                        else:
                            for dx,dy in zip([-2,-2,-1,-1,1,1,2,2],[-1,1,-2,2,-2,2,-1,1]):
                                new_x = i+dx
                                new_y = j+dy
                                if new_x >=0 and new_x <N and new_y >=0 and new_y<N:
                                    dp[i][j][k] += 1/8*dp[new_x][new_y][k-1]
    
            return dp[r][c][K]
    

    C++:

    class Solution {
    public:
        double knightProbability(int N, int K, int r, int c) {
            vector<vector<vector<double>>> dp(N,vector<vector<double>>(N,vector<double>(K+1,0)));
            int direction[][2] = {{-1, -2}, {1, -2}, {-1, 2}, {1, 2}, {-2, -1}, {-2, 1}, {2, -1}, {2, 1}};
            for(int k=0;k<K+1;++k){
                for(int i=0;i<N;++i){
                    for(int j =0;j<N;++j){
                        if(k==0){
                            dp[i][j][k] = 1.0;
                            continue;
                        }
                        for(int l=0;l<8;++l){
                            int dx=direction[l][0],dy=direction[l][1];
                            int new_x = i+dx,new_y=j+dy;
                            if(new_x>=0 && new_x<N && new_y>=0 && new_y<N)
                                dp[i][j][k] += 1.0/8.0*dp[new_x][new_y][k-1];
                        }
                    }
                }
            }
            return dp[r][c][K];
        }
    };
    
  • 相关阅读:
    Linux input子系统学习总结(一)---- 三个重要的结构体
    DRM/KMS 基本组件介绍
    Framebuffer 驱动学习总结(二)---- Framebuffer模块初始化
    Framebuffer 驱动学习总结(一) ---- 总体架构及关键结构体
    Linux USB驱动学习总结(三)---- USB鼠标的加载、初始化和通信过程
    Linux USB驱动学习总结(一)---- USB基本概念及驱动架构
    使用Python调用动态库
    使用 SignalR与SSE(Sever sent event)向客户端推送提示信息
    在IDEA下使用Spring Boot的热加载(Hotswap)
    使用Spring boot + jQuery上传文件(kotlin)
  • 原文地址:https://www.cnblogs.com/hellojamest/p/12273644.html
Copyright © 2011-2022 走看看