今天学了广度优先搜索(bfs)以及AC的题
什么是bfs?
BFS(广度优先搜索)是一种图遍历算法,它从一个起始点开始,逐层扩展搜索范围,直到找到目标节点为止。这种算法通常用于解决“最短路径”问题,比如在迷宫中找到从起点到终点的最短路径
首先,你会从起点开始,检查所有与它相邻的位置,也就是距离起点为1的位置, 然后,你会继续向外扩展,检查所有距离起点为2的位置,以此类推,直到找到出口
在BFS中,你可以使用队列来存储待搜索的节点。起始点首先加入队列中,然后不断从队列中取出节点,检查它是否是目标节点。如果不是,就将它的所有未被访问过的邻居加入队列中。这样,队列中的节点总是按照它们距离起点的距离排序,先加入队列的节点总是先被取出来搜索。
通过这种方式,BFS可以找到起点到目标节点的最短路径。在实际应用中,BFS还可以用于拓扑排序、连通性检测等问题的解决。
废话不多说上题目
题目链接:https://www.luogu.com.cn/problem/P1825
题解:很明显这是一道bfs并且还使用了队列,这道题注意的是他的这个传送装置,进了传送装置就要改变位置,首先创建结构体队列内部三个成员坐标x,y以及temp表示时间,将起点入列并用个二维数组标记点已经走过;向四个方向进行搜索即可;
AC代码:
#include <iostream>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
using ll = long long;
#define up(h, n) for (int i = h; i <= n; i++)
#define down(h, n) for(int i = h; i >= n; i--)
#define wh(x) while(x--)
#define node struct node
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
constexpr int N = 200005;
constexpr int mod = 1e9 + 7;
node{
int x;
int y;
int temp;//时间
};
const int next1[4][2] = { {1,0},{-1,0},{0,1},{0,-1} };// 四个方向
bool book[N][N];
char s[N][N];
int n, m,sum;
queue<node>q;//创建队列
void top(int *x, int *y) { //传送装置更换位置
up(1, n) {
for (int j = 1; j <= m; j++){
if (s[i][j] == s[*x][*y] && (i != *x || j != *y)) {
*x = i; *y = j;
return;
}
}
}
}
int bfs(int x, int y) {
q.push({ x,y,0 });
book[x][y] = true;
while (q.size()) {
node t = q.front();
q.pop();
if (s[t.x][t.y] == '=') {// 判断是否到达终点
return t.temp;
}
if (s[t.x][t.y] >= 'A' && s[t.x][t.y] <= 'Z') top(&t.x, &t.y);//判断是否是传送装置
up(0, 3) { // 遍历四个方向
int tx = t.x + next1[i][0];
int ty = t.y + next1[i][1];
if (tx >= 1 && tx <= n && ty >= 1 && ty <= m && book[tx][ty] == false && s[tx][ty] != '#') {
book[tx][ty] = true;
q.push({ tx,ty,t.temp + 1 }); // 入列
}
}
}
}
int main()
{
ios;
cin.tie(0); cout.tie(0);
cin >> n >> m;
int x, y;
up(1, n) {
for (int j = 1; j <= m; j++) {
cin >> s[i][j];
if (s[i][j] == '@') {
x = i; y = j;
}
}
}
sum = bfs(x, y);
cout << sum << '\n';
return 0;
}
题目链接:八皇后
题解:这题的话首先要读懂意思就是每行每列每条对角线只有一个棋子,知道这个便定义四个数组分别用来计数和标记即可最后运用dfs搜索原理即可AC.
AC代码;
#include <iostream>
#include <string>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <stack>
using namespace std;
using ll = long long;
#define up(h,n) for(int i=h;i<=n;i++)
#define down(h,n) for(int i=h;i>=n;i--)
#define wh(x) while(x--)
#define node struct node
#define ios ios::sync_with_stdio(false)
constexpr int N = 100005;
constexpr int mod = 1e9 + 7;
typedef int SElemType;
int n,sum=0;
int a[105], b[105], c[105], d[105]; //a存结果,b数组用来标记,c,d用来标记对角线
void dfs(int x)
{
if (x > n) {
sum++;
if (sum <= 3) { // 前三组数据输出
up(1, n) {
cout << a[i] << ' ';
}
cout << '\n';
}
}
up(1, n) {
if (b[i] == 0 && c[x + i] == 0 && d[x - i + 13] == 0) {
a[x] = i;
b[i] = 1; c[x + i] = 1; d[x - i + 13] = 1;// +13是因为两个相减可能为负数,
dfs(x + 1); // n最大是13所以直接就+13
b[i] = 0; c[x + i] = 0; d[x - i + 13] = 0;// 回溯
}
}
}
int main()
{
cin >> n;
dfs(1);
cout << sum << '\n';
return 0;
}
题目链接:求先序排列
题解:这道题的话,是二叉树的遍历序列,知道后序和中序遍历的话,后序的最后一个节点是根结点,然后找到中序根结点的位置分成左子树和右子树,然后又对左子树和右子树进行同样的操作即可得出答案;
AC代码:
#include <iostream>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
using ll = long long;
#define up(h,n) for(int i=h;i<=n;i++)
#define down(h,n) for(int i=h;i>=n;i--)
#define wh(x) while(x--)
#define node struct node
#define ios ios::sync_with_stdio(false)
constexpr int N = 305;
constexpr int mod = 1e9 + 7;
typedef int SElemType;
string a;
string b;
void dfs(string s, string k) {
if (s.size() > 0) {
char ch = k[k.size() - 1];//找到后序的根结点
cout << ch;
int t = s.find(ch); // find用来查找位置
dfs(s.substr(0, t), k.substr(0, t));// substr用来截取字符串
dfs(s.substr(t + 1), k.substr(t, k.size()-t- 1));//递归左右两边子树
}
else return ;
}
int main()
{
cin >> a;
cin >> b;
dfs(a, b);
return 0;
}
题目链接