1219 马走日

让本羊羔算算,我多久没更新信息学奥赛一本通了?

上一次发是8月8日,这一次是……

如果看懂了我第一篇讲搜索的文章,你动动脑筋就能做这道题


目录

原题再现

1219:马走日

【题目描述】

【输入】

【输出】

【输入样例】

【输出样例】

分析题意

确定算法

羊羔之详细讲解

代码呈现(无注释)


原题再现

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<

大家学会了吗?

拜拜!

你可能感兴趣的:(信息学奥赛一本通专讲,算法,c++)