题目描述
棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A 点(0,0)、B 点 (n,m),同样马的位置坐标是需要给出的。
现在要求你计算出卒从 A 点能够到达 B 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个正整数,分别表示 B 点坐标和马的坐标。
输出格式
一个整数,表示所有的路径条数。
输入
6 6 3 3
输出
6
说明/提示
对于 100% 的数据,1≤n,m≤20,0≤ 马的坐标≤20。
题解
递推方法,刚开始令原点(1,1)的路径数为1,我的代码原点设定为(1,1),所以B的坐标和马的坐标输入之后要分别加 1。
用深度优先搜索会超时(明知道会超时还是试了一下…),所以最后还是用广度优先搜索+动态规划递推来遍历整个坐标图→→根据“当前坐标左方”和”上方“的坐标的路径数推出“当前坐标”的路径数。ac耗时2ms。
状态转移方程:m[i][j]=m[i-1][j]+m[i][j-1]
我的代码因为只有一个数组,并且受马控制的坐标存得值为-1,所以算出当前坐标的路径数的时候还要判断左方和上方的坐标是否为马控制的坐标(受马控制的坐标的提供的路径数为0)。
数组开大点(因为我主函数内部给马控制坐标赋值的时候少了一个特判,数组开小了会发生指针越界,数组开大点就不会错,或者可以加上一个特判)。
#include <bits/stdc++.h>
#include <algorithm>
using namespace std;
long long m[30][30],mark[30][30];
long long bx,by,hx,hy,cnt;
long long hdx[]={-2,-1,-2,-1,1,2,1,2},
hdy[]={-1,-2,1,2,-2,-1,2,1};
long long dx[]={1,0},dy[]={0,1};
struct node{
long long x,y;
};
void bfs(){
queue<node> q;
node t;
t.x=1,t.y=1;
q.push(t);
long long flag=0;
while(!q.empty()){
node temp=q.front();
q.pop();
if(flag){
if(m[temp.x-1][temp.y]==-1&&m[temp.x][temp.y-1]!=-1)
m[temp.x][temp.y]=0+m[temp.x][temp.y-1];
else if(m[temp.x-1][temp.y]!=-1&&m[temp.x][temp.y-1]==-1)
m[temp.x][temp.y]=m[temp.x-1][temp.y]+0;
else if(m[temp.x-1][temp.y]==-1&&m[temp.x][temp.y-1]==-1)
m[temp.x][temp.y]=0;
else
m[temp.x][temp.y]=m[temp.x-1][temp.y]+m[temp.x][temp.y-1];
}
for(long long i=0;i<2;i++){
node tt;
tt.x=temp.x+dx[i];
tt.y=temp.y+dy[i];
if(m[tt.x][tt.y]!=-1&&tt.x<=bx&&tt.y<=by&&!mark[tt.x][tt.y]){
q.push(tt);
mark[tt.x][tt.y]=1;
}
}
flag=1;
}
}
int main() {
scanf("%lld%lld%lld%lld",&bx,&by,&hx,&hy);
bx+=1,by+=1;
hx+=1,hy+=1;
m[hx][hy]=-1;
m[1][1]=1;
for(long long i=0;i<8;i++){
int xx=hx,yy=hy;
xx+=hdx[i];
yy+=hdy[i];
if(xx>0&&yy>0)
m[xx][yy]=-1;
}
bfs();
printf("%lld\n",m[bx][by]);
return 0;
}