题目描述

棋盘上 AA 点有一个过河卒,需要走到目标 BB 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 CC 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

棋盘用坐标表示, AA 点 (0, 0)(0,0) 、 BB 点 (n, m)(n,m) ( nn , mm 为不超过 2020 的整数),同样马的位置坐标是需要给出的。

现在要求你计算出卒从 AA 点能够到达 BB 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

输入输出格式

输入格式:

 

一行四个数据,分别表示 BB 点坐标和马的坐标。

 

输出格式:

 

一个数据,表示所有的路径条数。

 

输入输出样例

输入样例#1: 复制
6 6 3 3
输出样例#1: 复制
6

说明

结果可能很大!

思路过程

第一感觉,就想用深度优先搜索做,然后里面wa最后还超时一发。。。后面自己仔细想了一下,如果深度优先和广度优先,那么肯定是不对的,因为无论是深搜还广度优先搜索,最坏结果都是需要遍历每个点,这样遍历每个点复杂度是2^n,稳稳的超时。。。后来想想,其实不妨这样想,每个点只可能从上面和左边推过来,这样就从第一个点往后推即可,转移方程:

dp[i][j]=dp[i-1][j]+dp[i][j-1]

这应该是递推,不能算是动态规划,最后提醒一点,在判断马控制的位置需要判断一下边界条件不然。。。会被坑(下次一定要记住)

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int mv[2][10]={{0,-2,-2,-1,-1,1,1,2,2},{0,1,-1,2,-2,2,-2,1,-1}};//用二维数值写方向很方便
long long dp[25][25];
bool visit[25][25];
int main(){
  int nx,ny,hx,hy;
  scanf("%d%d%d%d",&nx,&ny,&hx,&hy);
  memset(dp,0,sizeof(dp));
  memset(visit,0,sizeof(visit));
  for(int i=1;i<=8;i++){
    if (hx+mv[0][i]>=0 && hx+mv[0][i]<=nx && hy+mv[1][i]>=0 && hy+mv[1][i]<=ny)
    visit[hx+mv[0][i]][hy+mv[1][i]]=1;
  }
  visit[hx][hy]=1;
  dp[0][0]=1;
  for(int i=0;i<=nx;i++){
    for(int j=0;j<=ny;j++){
      if (i)
         dp[i][j]+=dp[i-1][j];
      if (j)
         dp[i][j]+=dp[i][j-1];
          dp[i][j]*=!visit[i][j];
    }
  }
  printf("%lld",dp[nx][ny]);
  return 0;
}