您的位置:首页 > 编程语言 > C语言/C++

竞赛题目-【NOIP2012】马拦过河卒

2017-06-04 07:24 316 查看

【NOIP2002】马拦过河卒

题目描述:

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

棋盘用坐标表示,A点(0, 0)、B点(n, m)(n, m为不超过20的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

输入:

第1行:4个数据,分别表示B点坐标和马的坐标。

输出:

第1行:1个数据,表示所有的路径条数。

样例输入:

6 6 3 3

样例输出:

6

题目分析:

与“母亲的牛奶”(参考【USACO TRAINING】母亲的牛奶)一样,是一道经典的 搜索题目,用深度优先搜索和广度优先搜索均能完成,这里作者采用深度优先搜索

首先,我们需要知道棋盘的边界(这里指有意义的最小边界)。由题目描述:

可以向下、或者向右

我们知道:要到达B点,则卒当前的位置不能在B点下方或者左边;因此,最小边界的右下角为B点。根据输入,则当前坐标x小于等于B点坐标n,当前坐标y小于等于B点坐标m

根据题目:

该马所在的点和所有跳跃一步可达的点称为对方马的控制点

我们需要定义一个二维bool数组表示棋盘中可以走的位置。读入马的坐标后,立即将马的9个控制点(注意马本身的位置也是控制点)在bool数组中的位置改为true(不可走)。

然后我们需要设置一个向量(只有两种方向可以选择)用于改变当前坐标的值——
int F[2][2]={{1,0},{0,1}}
,再定义一个tot保存答案。定义(p,q)为当前坐标,判断坐标(p,q)是否在控制点上(若是,则continue返回),调用函数自身进行下一次搜索。这里有一个问题,我们在做这样类似于迷宫的问题时,为避免重复,常常会将走过的位置改为true(不可走),但是这里并没有。程序并没有错,原因在本题要求卒只能向右或向下走,这样就已经避免了重复。当当前位置就是B点时,tot++,return结束本轮搜索。最后输出结果。

程序样例:

#include<cstdio>
#include<cstring>
bool chess[25][25];
int Bx,By,Hx,Hy,HORSE[8][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}},F[3][2]={{1,0},{0,1}},tot;
//B点坐标,马坐标,马的除本身的8个控制点,向量,答案
void flag(int x,int y) //深度优先搜索
{
if(x==Bx && y==By) //当前位置是B点
{
tot++;
return;
}
for(int i=0;i<2;i++)
{
int nx=x+F[i][0],ny=y+F[i][1]; //当前坐标
if(nx<0 || nx>Bx || ny<0 || ny>By || chess[nx][ny]) continue; //越界或是控制点
flag(nx,ny); //新一轮搜索
}
}
int main()
{
scanf("%d%d%d%d",&Bx,&By,&Hx,&Hy);
chess[Hx][Hy]=true; //马本身
for(int i=0;i<8;i++) //其余8个控制点
{
int nx=Hx+HORSE[i][0],ny=Hy+HORSE[i][1];
if(nx<0 || nx>=Bx || ny<0 || ny>=By) continue;
chess[nx][ny]=true;
}
flag(0,0);
printf("%d\n",tot);
return 0;
}
/*
Language: C++
Result: 正确
Time:788 ms
Memory:1028 kb
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 竞赛算法