输入一行数字,包含3个参数x,y,k
输出一个数,代表有几种
7 7 10
515813
https://www.nowcoder.com/questionTerminal/c45704a41617402fb5c34a1778bb2645
把象棋棋盘放入第一象限,棋盘的最左下角是(0, 0)位置,那么整个棋盘就是横坐标上9条线,纵坐标上10条线的区域给你三个参数x、y、k,返回“马”从(0, 0)位置出发,必须走k步,最后落在(a,b)上的方法有多少种
象棋中的规则:马只能日字跳
所以下面的跳法是错的:

正确的跳法:
从(x,y)位置跳,可以往八个位置跳,有八种跳法
p1:(x+2,y+1) p2:(x+1,y+2) p3:(x-1,y+2) p4:(x-2,y+1)
p5:(x-2,y-1) p6:(x-1,y-2) p7:(x+1,y-2) p8:(x+2,y-1)

递归全展开,一个位置8种可能性,一共跳k步,所以暴力方法时间复杂度:O(8^k)
这八个位置分别再往后跳,最后到达(a,b)的方法数之和就是从(x,y)出发到达(a,b)的方法数
暴力方法在OJ超时!
/*
process函数的含义:
当前来到的位置是(x,y),还剩下rest步需要跳,跳完rest步之后正好跳到(a,b)的方法数是多少
*/
int process1(int x, int y, int rest, int a, int b)\
{
    //防止越界: 棋盘是10*9   
    //范围:x:0~9  y:0~8
    if (x < 0 || x > 9 || y < 0 || y > 8) {
        return 0;
    }
    //base case:剩余步数为0,如果刚好跳到了(a,b)位置就是一种方法,否则不是
    if (rest == 0) 
    {
        return (x == a && y == b) ? 1 : 0;
    }
    //从(x,y)分别往八个方向跳,剩rest-1步走, 要跳到(a,b) 的方法数 
    int ways = 0;
    ways += process1(x + 2, y + 1, rest - 1, a, b);
    ways += process1(x + 1, y + 2, rest - 1, a, b);
    ways += process1(x - 1, y + 2, rest - 1, a, b);
    ways += process1(x - 2, y + 1, rest - 1, a, b);
    ways += process1(x - 2, y - 1, rest - 1, a, b);
    ways += process1(x - 1, y - 2, rest - 1, a, b);
    ways += process1(x + 1, y - 2, rest - 1, a, b);
    ways += process1(x + 2, y - 1, rest - 1, a, b);
    return ways;
}
int jump1(int a, int b, int k)
{
    //返回从(0,0)位置开始跳,跳k步,最后跳到(a,b)的方法数
    return process1(0, 0, k,a,b);
}
int main()
{
    cout << jump1(7, 7, 10) << endl;//515813
    return 0;
} a,b是固定参数,每次调用都不会变,而x,y,k每次调用过程都会变,因此process函数的调用结果取决于 x y k的值,我们只要用一个三维表来记录每个调用过程的返回值便能大大提高
x范围:09 y范围:08 rest的范围:0~k  所以开辟10*9*(k+1)的三维表
vector<vector<vector<int>>> dp(10, vector<vector<int>>(9, vector<int>(k + 1,-1)));
最初所以元素初始化为-1,表示每个位置都没有算过

记忆化搜索在这里OJ能过!
/*
process函数的含义:
当前来到的位置是(x,y),还剩下rest步需要跳,跳完rest步之后正好跳到(a,b)的方法数是多少
*/
int process2(int x, int y, int rest, int a, int b, vector<vector<vector<int>>>& dp)
{
    //防止越界: 棋盘是10*9   
    //范围:x:0~9  y:0~8
    if (x < 0 || x > 9 || y < 0 || y > 8) {
        return 0;
    }
    if (dp[x][y][rest] != -1)//如果值不为-1.说明之前算过这个过程,直接在表中拿值
    {
        return dp[x][y][rest];
    }
    //base case:剩余步数为0,如果刚好跳到了(a,b)位置就是一种方法,否则不是
    if (rest == 0)
    {
        int ans =  (x == a && y == b) ? 1 : 0;
        dp[x][y][rest] = ans;
        return ans;
    }
    //从(x,y)分别往八个方向跳,剩rest-1步走, 要跳到(a,b) 的方法数 
    int ways = 0;
    ways += process2(x + 2, y + 1, rest - 1, a, b, dp);
    ways += process2(x + 1, y + 2, rest - 1, a, b, dp);
    ways += process2(x - 1, y + 2, rest - 1, a, b, dp);
    ways += process2(x - 2, y + 1, rest - 1, a, b, dp);
    ways += process2(x - 2, y - 1, rest - 1, a, b, dp);
    ways += process2(x - 1, y - 2, rest - 1, a, b, dp);
    ways += process2(x + 1, y - 2, rest - 1, a, b, dp);
    ways += process2(x + 2, y - 1, rest - 1, a, b, dp);
    dp[x][y][rest] = ways;
    return ways;
}
//x范围:0~9 y范围:0~8 rest的范围:0~k
//所以开辟10*9*(k+1)的三维表
int jump2(int a, int b, int k)
{
    //返回从(0,0)位置开始跳,跳k步,最后跳到(a,b)的方法数
    vector<vector<vector<int>>> dp(10, vector<vector<int>>(9, vector<int>(k + 1,-1)));
    process2(0, 0, k, a, b,dp);
    //dp[i][j][k]的含义:从(i,j)位置,跳k步跳到目标位置(a,b)的方法数
    return dp[0][0][k];
} 使用dp表的时间复杂度:O(10*9*K ) ->时间复杂度:O(K)
任何的rest层的东西 只依赖rest-1层,所以我们先把第0层填好,再填第一层.... 从上往下填
注意:可能存在下标越界的情况,所以封装一个函数在dp表中拿值
//为了防止下标越界,封装一个函数检测, 不越界才返回表中的值
int pick(vector<vector<vector<int>>>& dp, int x, int y, int rest)
{
    if (x < 0 || x > 9 || y < 0 || y > 8) 
    {
        return 0;
    }
    return dp[x][y][rest];
}
int jump3(int a, int b, int k)
{
    vector<vector<vector<int>>> dp(10, vector<vector<int>>(9, vector<int>(k + 1)));
    //rest=0时(第0层),只有x=a,y=b位置是1 剩下第0层的位置是0
    dp[a][b][0] = 1;
    //从第一层开始填,填到第k层
    for (int rest = 1; rest <= k; rest++) 
    {
        for (int x = 0; x < 10; x++)
        {
            for (int y = 0; y < 9; y++)
            {
                int ways = 0;
                ways += pick(dp, x + 2, y + 1, rest - 1);
                ways += pick(dp, x + 1, y + 2, rest - 1);
                ways += pick(dp, x - 1, y + 2, rest - 1);
                ways += pick(dp, x - 2, y + 1, rest - 1);
                ways += pick(dp, x - 2, y - 1, rest - 1);
                ways += pick(dp, x - 1, y - 2, rest - 1);
                ways += pick(dp, x + 1, y - 2, rest - 1);
                ways += pick(dp, x + 2, y - 1, rest - 1);
                dp[x][y][rest] = ways;
            }
        }
    }
    //dp[i][j][k]的含义:从(i,j)位置,跳k步跳到目标位置(a,b)的方法数
    //题目要求是从(0,0)出发,目标是跳k步到(a,b)
    return dp[0][0][k];
}
                                                                                    import java.util.*;
public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        int y = sc.nextInt();
        int nums = sc.nextInt();
        int[][][] dp = new int[9][10][nums+1];
        dp[0][0][0] = 1;
        for(int i=1; i<=nums; i++){
            for(int j=0; j<9; j++){
                for(int k=0; k<10; k++){
                    dp[j][k][i] += getValue(i-1,j-1,k+2,dp);
                    dp[j][k][i] += getValue(i-1,j-2,k+1,dp);
                    dp[j][k][i] += getValue(i-1,j-2,k-1,dp);
                    dp[j][k][i] += getValue(i-1,j-1,k-2,dp);
                    dp[j][k][i] += getValue(i-1,j+1,k-2,dp);
                    dp[j][k][i] += getValue(i-1,j+2,k-1,dp);
                    dp[j][k][i] += getValue(i-1,j+2,k+1,dp);
                    dp[j][k][i] += getValue(i-1,j+1,k+2,dp);
                }
            }
        }
        System.out.println(dp[x][y][nums]);
    }
    
    public static int getValue(int l,int x,int y,int[][][] dp){
        if(x<0 || x>=9 || y<0 || y>=10){
            return 0;
        }
        return dp[x][y][l];
    }
} import java.util.*;
public class Main{
    
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int x = scanner.nextInt();
        int y = scanner.nextInt();
        int k = scanner.nextInt();
        
        System.out.print(waysdp(k, x, y) + "");
    }
    
    // 动态规划
    public static int waysdp(int k, int x, int y){
        int[][][] dp = new int[9][10][k + 1];
        // 达成条件
        dp[x][y][0] = 1;
        for(int rest = 1; rest < k + 1; rest++){
            for(int i = 0; i < 9; i++){
                for(int j = 0; j < 10; j++){
                    dp[i][j][rest] = (getValue(dp, i - 1, j - 2, rest - 1) + 
                        getValue(dp, i - 2, j - 1, rest - 1) + 
                        getValue(dp, i - 1, j + 2, rest - 1) + 
                        getValue(dp, i - 2, j + 1, rest - 1) + 
                        getValue(dp, i + 1, j - 2, rest - 1) + 
                        getValue(dp, i + 2, j - 1, rest - 1) + 
                        getValue(dp, i + 1, j + 2, rest - 1) + 
                        getValue(dp, i + 2, j + 1, rest - 1));
                }
            }
        }
        return dp[0][0][k];
    }
    
    public static int getValue(int[][][] dp, int a, int b, int rest){
        if(a > 8 || a < 0 || b > 9 || b < 0) {
            return 0;
        }
        return dp[a][b][rest];
    }
    
    public static int recursion(int a , int b, int rest, int x, int y){
        if(a > 8 || a < 0 || b > 9 || b < 0) {
            return 0;
        }
        if(rest == 0){
            return  a == x && b == y ? 1 : 0;
        }
        return recursion(a - 1, b - 2, rest -1, x, y) + 
            recursion(a - 2, b - 1, rest -1, x, y) + 
            recursion(a - 1, b + 2, rest -1, x, y) + 
            recursion(a - 2, b + 1, rest -1, x, y) + 
            recursion(a + 1, b - 2, rest -1, x, y) + 
            recursion(a + 2, b - 1, rest -1, x, y) + 
            recursion(a + 1, b + 2, rest -1, x, y) + 
            recursion(a + 2, b - 1, rest -1, x, y);
    }
    
}