首页 > 其他分享 >洛谷P1443 马的遍历(BFS广度优先搜索)

洛谷P1443 马的遍历(BFS广度优先搜索)

时间:2023-11-30 23:32:09浏览次数:34  
标签:洛谷 P1443 temp int BFS 405 nex sta isvis

这道题只要求输入最小步数即可,而且数据的个数较大,所以优先采用BFS(广度优先搜索):

广度优先搜索,即以数据搜索的广度优先,换句话说就是每一次操作都将所有可能的结果存储下来,随后对数据进行下一步处理,注意是对每组数据都只进行一次处理,如果是一条路走到头,这就变成了深度优先搜索(DFS)。

而基于这个原理,我们可以用队列来处理每一次操作所产生的可能结果,并对数据进行下一步处理,符合队列先进先出(FIFO)的特点。

#include<queue>//引入队列的头文件queue
template <class T, class Container = deque<T> > class queue;//queue的定义

可以看到队列的实现有赖于deque,deque即双端队列,队列只有一端负责输入,另一端负责输出,而双端队列允许从两端写入读出数据。

下面我们定义一个队列,并将其内部数据类型设为pair<int ,int>来存储其坐标

queue<pair<int, int>> q;

此外,像DFS一样,我们要防止遍历回到之前的已经遍历过的点(虽然DFS有回溯操作,但这两者并不是一回事)从而造成死循环,所以我们要定义一个bool类型的数组,用来记录每个坐标是否被访问过。

bool isvis[405][405];

再根据题意,因为马走的是日字形(不同于走迷宫的一步一步,再加上题目强调了是在棋盘上,所以并没有歧义),所以我们要定义一个数组来表示马的所有可能走向,并在循环中对当前马所在的坐标进行遍历操作。

int d[8][2] = { {1,-2},{1,2},{2,-1},{2,1},{-1,2},{-1,-2},{-2,1},{-2,-1} };//注意不要搞错了,做到不重不漏

这时还有个重要的问题,如何表示当前的遍历深度,即如何输出当前马走了多少步。我之前尝试了用一个变量来表示其所遍历的深度,但一直都存在逻辑问题,后来在题解中看到别人用数组来存储遍历深度,即当前节点的深度等于上一个节点的深度加1,后来我想了一下,这其实是一种递归的思想,可以套用到一些其他的BFS题目中,下面是我学习到的表示深度的解法:

int v_nex[405][405];
v_nex[n_x - 1][n_y - 1] = v_nex[temp.first - 1][temp.second - 1] + 1;

这样所有的准备工作都已经基本完成,下面我们将实现该部分的核心代码:

while (!q.empty()) {//empty()是队列中的内置函数,用来判断队列是否为空,如果为空,则返回

		temp = q.front();
		q.pop();
		for (int i = 0; i < 8; i++) {
			n_x = temp.first + d[i][0];
			n_y = temp.second + d[i][1];
			if (n_x<1 || n_x>n || n_y<1 || n_y>m) {
				continue;
			}
			if (isvis[n_x - 1][n_y - 1]) {
				continue;
			}
			q.push({ n_x,n_y });
			isvis[n_x - 1][n_y - 1] = 1;
			v_nex[n_x - 1][n_y - 1] = v_nex[temp.first - 1][temp.second - 1] + 1;
		}
	}

因为题目要求输出矩阵内所有的点,所以我们输出是要用for的嵌套循环来输出所有点的深度(即它所需的最少步数)。

for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++){
			if (i == sta_x && j == sta_y) {
				cout << 0 << ' ';
				continue;
			}
			if (v_nex[i - 1][j - 1] == 0) {
				cout << -1 << ' ';
				continue;
			}
			cout << v_nex[i - 1][j - 1] << ' ';
		}
		cout << endl;
	}

为了满足题意,我们还要对特值进行if判断加以输出。

接下来还要说明为什么BFS输出的一定是最小值,因为在前文中特意强调了BFS的一个特性,即每次对可能的节点只进行一次操作,不像DFS一样一条路走到头,在所有情况都只进行一次操作的前提下,先出来的答案必然是最小值,所以BFS一般用来解决最小值问题。

下面是完整代码:

#include<queue>
#include<iostream>
#include<cstring>
using namespace std;


queue<pair<int, int>> q;
int n, m, sta_x, sta_y, n_x, n_y;
int v_nex[405][405];
int d[8][2] = { {1,-2},{1,2},{2,-1},{2,1},{-1,2},{-1,-2},{-2,1},{-2,-1} };
pair<int, int> temp;
bool isvis[405][405];

int main(void) {
	cin >> n >> m >> sta_x >> sta_y;
	q.push({ sta_x,sta_y });
	memset(isvis, 0, sizeof isvis);
	isvis[sta_x - 1][sta_y - 1] = 1;

	while (!q.empty()) {

		temp = q.front();
		q.pop();
		for (int i = 0; i < 8; i++) {
			n_x = temp.first + d[i][0];
			n_y = temp.second + d[i][1];
			if (n_x<1 || n_x>n || n_y<1 || n_y>m) {
				continue;
			}
			if (isvis[n_x - 1][n_y - 1]) {
				continue;
			}
			q.push({ n_x,n_y });
			isvis[n_x - 1][n_y - 1] = 1;
			v_nex[n_x - 1][n_y - 1] = v_nex[temp.first - 1][temp.second - 1] + 1;
		}
	}

	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++){
			if (i == sta_x && j == sta_y) {
				cout << 0 << ' ';
				continue;
			}
			if (v_nex[i - 1][j - 1] == 0) {
				cout << -1 << ' ';
				continue;
			}
			cout << v_nex[i - 1][j - 1] << ' ';
		}
		cout << endl;
	}
	return 0;
}

标签:洛谷,P1443,temp,int,BFS,405,nex,sta,isvis
From: https://blog.51cto.com/u_16271511/8634745

相关文章

  • 广度优先搜索(BFS)
    一、广搜介绍广度优先搜索是一种暴力算法,通过遍历一整张图来找寻结果。一般是使用队列来实现1.原理首先我们将根节点加入队列,然后遍历这个节点的全部方向,如果有满足条件的节点出现,就将其加入队列。在全部方向遍历完之后,我们将遍历的节点出队列。然后接着重复上述的操作,直到队......
  • [洛谷P5966] [BZOJ4344] [POI2016] Hydrorozgrywka
    题解建出原图的圆方树。由于原图无重边,不妨把桥看作二元环建树,这样圆点只与方点直接相连。圆方树定某一圆点为根后,若点\(u\)是圆点,定义点\(u\)的子仙人掌为点\(u\)子树中的圆点在原图的导出子图,定义该子仙人掌的根为点\(u\);若点\(u\)是方点,定义点\(u\)的子仙人掌为点......
  • P1090 [NOI洛谷P2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G
    可以用堆来实现,或者更简单一点的优先队列优先队列:#include<queue>priority_queue<int,vector<int>,greater<int>>q;因为每次合并后,最小的两个值都会更新,所以可以很好的利用优先队列内元素有序的特点,减少因反复排序带来的时间复杂度;一开始我用STL自带的排序sort,报了5个TLE,后来意......
  • 洛谷P5719 分类平均
    intmain(){ intn,k,add=0,abb=0; doublesum=0,cnt=0; cin>>n>>k; for(inti=1;i<=n;++i) if(i%k==0) { add++; sum+=i; } cout<<fixed<<setprecision(1)<<sum/add<<''; for(inti=1;i<=n;++i) if(i%k......
  • 堆和优先队列(洛谷P3378)
    1.优先队列解决:优先队列:头文件和定义:#include<queue>template<classT,classContainer=vector<T>,classCompare=less<typenameContainer::value_type>>classpriority_queue;可表达为以下形式:priority_queue<Type,Container,Functional>type:即数据的类型Co......
  • AcWing 920. 最优乘车 (抽象建图 + bfs
    package算法提高课;importjava.util.Arrays;importjava.util.LinkedList;importjava.util.Queue;importjava.util.Scanner;publicclassacw920{/***本题的建图方式:*我们对于每一个巴士路线进行观察,发现从前面的站走向这一条巴士路线......
  • OI_problem 玛丽卡_洛谷P1186
    题意一个\(N\)个点\(M\)条边的带边权无向图,要求输出最小的\(V\)使得不管去掉哪一条边,都存在从\(1\)到\(n\)的路径使得边权和不超过\(V\)。思路感觉朴素不太好做,考虑二分。对于一个二分值,即要判断在关于这个值的生成图中,\(1\)和\(n\)在不在一个边双里。考......
  • 洛谷 P4872 OIer们的东方梦 题解
    前言一个下午,一个晚上,一个早上,可以算是一天了吧,终于调出了这道题,纪念一下吧!!!食用更佳。这道题其实就是一道简简单单的BFS模(du)板(liu)题。说难不难,简单不简单,虽然没有难的算法,但是就是码量一百多行,比较难调。题目难度绿,思维难度橙,代码难度蓝。真是个绝世好题。题目意思就是一......
  • 洛谷P3161 [CQOI2012] 模拟工厂题解
    P3161[CQOI2012]模拟工厂题解。题目其实发现这是一道状压,发现这道题是一道数学题,其实就很简单了。对于每一次的订单我们可以设:\(time\)为距离下一个订单的时间。\(num\)为这个订单要生产的数量。\(x\)为生产能力。\(y\)的时间可以用来提高工厂的生产力。那我们就可以得......
  • 「杂题乱刷」洛谷P9515
    原题链接P9515「JOC-1A」限时签到题意简述有一条公路上有\(n\)个商店,每个商店分别在不同的时刻开放,求如何在\(t\)时刻之前到达\(f\)点并且到达最多开放的商店的数量,特别的,一个时刻只能走一格。解题思路这一道题是一道贪心题。首先,因为要在\(t\)时刻之前到达\(f\)......