【洛谷】P1443 马的遍历(C语言)【BFS】【队列】

马的遍历

题目描述

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

输入格式

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

输出格式

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

输入输出样例

输入 #1

3 3 1 1

输出 #1

0    3    2    
3    -1   1    
2    1    4    

说明/提示

数据规模与约定

对于全部的测试点,保证 1≤x≤n≤400,1≤y≤m≤400。

题解

马是走日字格的,这应该都知道的吧
首先本题的大致思路是从起始点出发,往八个方向走日字格,去往新的点,如果可以走到,就将那个点的步数加一,接着再从第一轮走到的点开始,往四周八个方向走日字格,如果可以走到且之前没有走到过,新走到的点的步数就等于上一个点的步数加一,再标记一下这个点走过了,接着就是这样循环,直到能到达的点全部走过一遍为止,走不到的点就是-1,最后输出棋盘上所有点的步数。
因此本题选择采用BFS的队列的思想来解决,但我这里没有用队列这个数据结构,只是用了队列的先进先出的思路。
首先要用一个二维数组来存整个棋盘(即每个点的步数),最后输出答案就是输出这个数组

int map[404][404] = { 0 };

再用一个一样大的二维数组存每个点是否被走过

int flag[404][404] = { 0 };

接着是一个用来表示队列的数组

int sq[160001][2];

这里行需要160001的原因是如果最坏情况下全部点都要入队一遍的话就是400*400=160000个点,因此需要这么多,虽然我第一次只开到40000也能过 ,两列表示点的横坐标和纵坐标。
最后,马从一个点出发,总共有八个方向可以走,用数组表示行动轨迹就是

xy[8][2] = { {1,2},{2,1},{-1,2},{-1,-2},{1,-2},{-2,-1},{-2,1},{2,-1} }

bfs函数部分

接下来就是bfs函数部分,首先设一个队头和队尾,队头初始化为0,队尾初始化为1(因为开始只有一个点)

int head = 0;
int tail = 1;

接着是while循环,条件为head < tail,意思是队不为空,head++表示入队,队头前移,取队头元素x,y坐标,并标记这个点走过了,再以这个点往八个方向扩展,不超边界且没走过的新点就入队,队尾加一,新点的步数为上一个点的步数加一,标记走过。

void bfs()
{
	int head = 0;//相当于队头指针,指示队头位置
	int tail = 1;//相当于队尾指针,指示队尾位置
	int xx;//用来存新点横坐标
	int yy;//用来存新点纵坐标
	while (head < tail)//只要队不为空
	{
		head++;//队列头元素出队,队头位置加一(后移)
		int x = sq[head][0];//取队头元素横坐标
		int y = sq[head][1];//取队头元素纵坐标
		flag[x][y] = 1;//标记队头的点(元素)走过了
		for (int i = 0; i < 8; i++)//8个方向日字格遍历
		{
			xx = x + xy[i][0];
			yy = y + xy[i][1];

			if (xx<1 || yy<1 || xx>n || yy>m)//超边界
			{
				continue;
			}
			if (flag[xx][yy] == 1)//走过
			{
				continue;
			}
			map[xx][yy] = map[x][y] + 1;//步数加一
			flag[xx][yy] = 1;//标记走过
			tail++;//新点入队,队尾位置加一(后移)
			sq[tail][0] = xx;//新点横坐标入队
			sq[tail][1] = yy;//新点纵坐标入队
		}
	}
}

主函数部分

int main()
{
	scanf("%d %d %d %d", &n, &m, &xxx, &yyy);
	sq[1][0] = xxx;//起始点横坐标入队
	sq[1][1] = yyy;//起始点纵坐标入队
	bfs();
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			if (flag[i][j] != 1)//从没走过
			{
				map[i][j] = -1;
			}
		}
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			printf("%d ", map[i][j]);//输出棋盘
		}
		printf("\n");
	}
	return 0;
}

完整代码

#include<stdio.h>
int xy[8][2] = { {1,2},{2,1},{-1,2},{-1,-2},{1,-2},{-2,-1},{-2,1},{2,-1} };
int map[404][404] = { 0 };
int sq[40000][2];
int flag[404][404] = { 0 };
int n, m;
int xxx, yyy;
void bfs()
{
	int head = 0;
	int tail = 1;
	int xx;
	int yy;
	while (head < tail)
	{
		head++;
		int x = sq[head][0];
		int y = sq[head][1];
		flag[x][y] = 1;
		for (int i = 0; i < 8; i++)
		{
			xx = x + xy[i][0];
			yy = y + xy[i][1];

			if (xx<1 || yy<1 || xx>n || yy>m)
			{
				continue;
			}
			if (flag[xx][yy] == 1)
			{
				continue;
			}
			map[xx][yy] = map[x][y] + 1;
			flag[xx][yy] = 1;
			tail++;
			sq[tail][0] = xx;
			sq[tail][1] = yy;
		}
	}
}
int main()
{
	scanf("%d %d %d %d", &n, &m, &xxx, &yyy);
	sq[1][0] = xxx;
	sq[1][1] = yyy;
	bfs();
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			if (flag[i][j] != 1)
			{
				map[i][j] = -1;
			}
		}
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			printf("%d ", map[i][j]);
		}
		printf("\n");
	}
	return 0;
}

提交结果

在这里插入图片描述

  • 42
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
广度优先遍历BFS)是一种图或树的遍历算法,其思想是从起点开始,按照距离递增的顺序依次访问与其相邻的节点,直到所有节点都被访问为止。以下是一个使用C语言实现BFS的示例代码: ``` #include <stdio.h> #include <stdbool.h> #define MAX_NODES 100 bool visited[MAX_NODES]; int queue[MAX_NODES]; int front = 0, rear = 0; void bfs(int graph[][MAX_NODES], int nodes, int start) { visited[start] = true; queue[rear++] = start; while (front < rear) { int curr = queue[front++]; printf("%d ", curr); for (int i = 0; i < nodes; i++) { if (graph[curr][i] && !visited[i]) { visited[i] = true; queue[rear++] = i; } } } } int main() { int graph[MAX_NODES][MAX_NODES]; int nodes, edges, start; // 读入图的节点数、边数和起点 scanf("%d %d %d", &nodes, &edges, &start); // 初始化邻接矩阵 for (int i = 0; i < nodes; i++) { for (int j = 0; j < nodes; j++) { graph[i][j] = 0; } } // 读入图的边并构建邻接矩阵 for (int i = 0; i < edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u][v] = graph[v][u] = 1; } // 初始化visited数组 for (int i = 0; i < nodes; i++) { visited[i] = false; } // 调用BFS函数 bfs(graph, nodes, start); return 0; } ``` 以上代码中,`graph` 是一个邻接矩阵,用于存储图的边信息。`visited` 数组用于记录每个节点是否被访问过。`queue` 数组用于存储待访问的节点。BFS算法的核心是 `bfs` 函数,它从起点 `start` 开始遍历图。在遍历过程中,每访问一个节点都将其标记为已访问,并将其相邻的未访问节点加入队列。在队列中,先加入的节点先被访问,保证了按照距离递增的顺序遍历图。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韬. .

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值