让本羊羔算算,我多久没更新信息学奥赛一本通了?
上一次发是8月8日,这一次是……
如果看懂了我第一篇讲搜索的文章,你动动脑筋就能做这道题
目录
原题再现
1219:马走日
【题目描述】
【输入】
【输出】
【输入样例】
【输出样例】
分析题意
确定算法
羊羔之详细讲解
代码呈现(无注释)
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 21398 通过数: 11227
马在中国象棋以日字形规则移动。
请编写一段程序,给定n×m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。
第一行为整数T(T < 10),表示测试数据组数。
每一组测试数据包含一行,为四个整数,分别为棋盘的大小以及初始位置坐标n,m,x,y。(0≤x≤n-1,0≤y≤m-1, m < 10, n < 10)。
每组测试数据包含一行,为一个整数,表示马能遍历棋盘的途径总数,0为无法遍历一次。
1 5 4 0 0
32
首先,我们要确定用什么算法做。
这道题是统计途径总数,用到枚举。
但普通枚举太麻烦,所以我想到了深度搜索。
如何确定图上所有点都被遍历过一次?用一个标记数组记录。
如何记录?用x,y坐标记录,也就是小学知识:数对
所以我们需要定义一个二维数组来标记(可以用布尔型true或false,也可以用整型1或2):
bool b[10][10];
马有八个位置可以走。设最初位置为x和y,那么这八个位置分别是:
x+2,y+1
x+1,y+2
x-1,y+2
x-2,y+1
x-2,y-1
x-1,y-2
x+1,y-2
x+2,y-1
我们可以通过传参(定义参数)来表示x和y,剩下的+1/-1/+2/-2用两个数组来表示就是:
int wx[8]={2,1,-1,-2,-2,-1,1,2};
int wy[8]={1,2,2,1,-1,-2,-2,-1};
我们需要用到for循环来遍历8个位置,再在里面定义两个变量,记录新的位置:
int nx=x+wx[i];
int ny=y+wy[i];
这个位置可能跳出了棋盘或重复了位置,所以我们需要进行判断:
if(nx>=0 && nx=0 && ny
如果条件不成立,那么进行下一次循环;
如果条件成立,说明这个点可以跳,就需要标记这个点跳过了:
b[nx][ny]=1;
什么情况下才能算一条途径?跳完所有点。
怎样判断跳完所有点?跳的点数(又称步数)等于棋盘上所有点,也就是n*m
我们又要定义一个参数step(简写s),来记录步数
如果s等于n*m,那么计数变量自增:
if(s==n*m) ans++;
否则继续遍历下一个点:
else{
dfs(nx,ny,s+1);
}
记得回溯!
b[nx][ny]=0;
以上是dfs函数里的代码,接下来是主函数:
有t组测试数据,那么定义、输入t,然后循环(建议使用while,更简便)
int t;
cin>>t;
while(t--)
按照题目定义、输入
因为有t组测试数据,所以要记得对变量或数组进行初始化
请注意!!!
1.dfs的参数step要从2开始,因为起点算一个点
2.起点算已经经过的一个点,所以标记数组b的起点要对起点进行标记!
好啦,这就是羊羔的讲解,还有一个更优化的方法待讲解,这就留给你思考吧……
提示:边界可以用标记数组判断
快去写代码吧!!!
#include
#include
using namespace std;
int n,m;
int wx[8]={2,1,-1,-2,-2,-1,1,2};
int wy[8]={1,2,2,1,-1,-2,-2,-1};
bool b[10][10];
int ans;
void dfs(int x,int y,int s)
{
for(int i=0;i<8;i++)
{
int nx=x+wx[i];
int ny=y+wy[i];
if(nx>=0 && nx=0 && ny>t;
while(t--)
{
int tx,ty;
cin>>n>>m>>tx>>ty;
ans=0;
memset(b,0,sizeof(b));
b[tx][ty]=1;
dfs(tx,ty,2);
cout<
大家学会了吗?
拜拜!