洛谷——p1443 马遍历

做这个题的时候,写了挺久,因为比较熟悉深搜,所以一下就想用深搜解题,但是题目不适合用这个深搜,因为不仅会重复搜索多次,还会因为数据较大而时间超限。

题目是这样的:

【题目描述】

有一个 n×m 的棋盘,在某个点 (x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。

【输入】

输入只有一行四个整数,分别为 n , m , x , y 。

【输出】

一个 n×m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 −1)。

样例输入

3 3 1 1

样例输出

0    3    2
3    -1    1
2    1    4

题目很短,用广搜简单粗暴。但是还是想试试深搜,如果数字不大的话,深搜也可以实现,思路是这样:把每一个点(马当前的点(x,y)除外)都当做起点进行一遍深搜,听起来有点吓人,因为这样操作还要判断到达这点的最短路径是多少,就是说每个点的深搜都包括若干次比较,找出最小的路径,存入数组,一个点接着一个点的深搜,很复杂...

深搜解题代码如下:(但是过不了)

#include
int n,m,x0,y0;
int book[405][405],flag[405][405];
int min=99999999;
void fun(int x1,int y1,int step)
{
	//记录方向数组,一共八个方向 
	int next[8][2]={2,1,-1,-2,-1,2,2,-1,1,2,1,-2,-2,1,-2,-1};
	int i,tx,ty;
	for(i=0;i<8;i++)
	{
		tx=x1+next[i][0];
		ty=y1+next[i][1];
		if(tx==x0&&ty==y0)
		{
			if(stepn||ty<=0||ty>m)
		continue;
		if(book[tx][ty]==0)
		{
			book[tx][ty]=1;
			fun(tx,ty,step+1);
			book[tx][ty]=0;//每一轮结束,取消标记 
		}
	}
	return ;
}
int main()
{
	int i,j;
	scanf("%d %d %d %d",&n,&m,&x0,&y0);
	//将每一个点代入 
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			//起点用book数组标记为 1 
			book[x0][y0]=1;
			//如果该点是起点就不用深搜 
			if(i!=x0||j!=y0)
			{
				fun(i,j,1);
				if(min<99999999)
				flag[i][j]=min;
				min=99999999;//每一个点深搜完,把 min 重新赋值,否则会出现多个数值相同的情况 
				int k,b;
				for(k=0;k

解题思路

一个平平无奇的广搜,首先定义结构体,存放一个点的 x 值,y 值,step(步数)。

然后用入队的方式,把未经过的点加入,加入时统计步数,然后一步步出队,最后队空,未统计步数的就是不能到达的点,然后得到结果。

代码如下:

#include
struct node
{
	int x;
	int y;
	int step;//存放走到这个点所用的步数 
};
int book[405][405],flag[405][405],n,m;
int main()
{
	int x0,y0,i,j;
	//记录方向的数组 
	int next[8][2]={2,1,1,2,1,-2,2,-1,-1,2,-1,-2,-2,1,-2,-1};
	struct node k[160005];
	scanf("%d %d %d %d",&n,&m,&x0,&y0);
	//将所有点认为是不能到达,全部赋值为 -1 
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		flag[i][j]=-1;
	}
	int tx,ty,tail=1,head=1;
	//将起点入队 
	k[tail].x=x0;
	k[tail].y=y0;
	k[tail].step=0;
	//并标记起点,避免重复经过 
	book[x0][y0]=1;
	tail++;
	while(headn||ty<=0||ty>m)
			continue;
			//要满足:未出界且先前没有经过该点 
			if(book[tx][ty]==0)
			{
				//第一件事标记我来过 
				book[tx][ty]=1;
				//然后入队 
				k[tail].x=tx;
				k[tail].y=ty;
				//到这点的步数就是:扩展到这点的队头步数(k[head].step)加上 1 
				k[tail].step=k[head].step+1;
				//把算出来的步数存入数组 
				flag[tx][ty]=k[tail].step;
				tail++;
			}
		}
		head++;	
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			//起点处输出为 0 
			if(i==x0&&j==y0)
			printf("0    ");
			else
			printf("%-5d",flag[i][j]);
		}
		printf("\n");
	}
	return 0;
} 

总结

广搜和深搜都各有优缺点,做题时要灵活运用,比如这题更适合用广搜bfs。

一般情况下,深度优先搜索法占内存少但速度较慢,广度优先搜索算法占内存多但速度较快,在距离和深度成正比的情况下能较快地求出最优解。

你可能感兴趣的:(题组,算法)