文章目录
BFS专题
bfs常用于求权值相同的最短路问题或者最小步数(操作次数)模型。
1.长草(多源bfs)
【题目链接】长草 - 蓝桥云课 (lanqiao.cn)
思路:多源bfs
所有起点先入队,用一个d[i][j]
数组记录当前点是第几次被扩展到的,然后不断扩展队头元素即可,后面就是基本的bfs模板操作了。
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
char g[N][N];
int d[N][N];
int n, m, k;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void bfs()
{
memset(d, -1, sizeof d);
queue<PII> q;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if(g[i][j] == 'g')
{
q.push({i, j});
d[i][j] = 0;
}
while(q.size())
{
auto t = q.front();
q.pop();
if(d[t.x][t.y] == k) break;// 扩展了k次后
for(int i = 0; i < 4; i ++)
{
int a = t.x + dx[i], b = t.y + dy[i];
if(a < 0 || a >= n || b < 0 || b >= m) continue;
if(d[a][b] != -1) continue;
if(g[a][b] != '.') continue;
d[a][b] = d[t.x][t.y] + 1;
q.push({a, b});
g[a][b] = 'g';// 被扩展了修改为g
}
}
}
int main()
{
// 请在此输入您的代码
cin >> n >> m;
for(int i = 0; i < n; i ++) cin >> g[i];
cin >> k;
bfs();
for (int i = 0; i < n; i ++ )
{
for (int j = 0; j < m; j ++ )
{
cout << g[i][j];
}
puts("");
}
return 0;
}
2.扩散(多源bfs)
这里再附上一道题同类目:
3.走迷宫(bfs最短路模板题)
【题目链接】走迷宫 - 蓝桥云课 (lanqiao.cn)
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 2010;
int g[N][N];
int d[N][N];
int n, m;
int x1, y1, x2, y2;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int bfs()
{
memset(d, -1, sizeof d);
queue<PII> q;
q.push({x1, y1});// 起点入队
d[x1][y1] = 0;
while(q.size())
{
auto t = q.front();
q.pop();
for(int i = 0; i < 4; i ++)
{
int a = t.x + dx[i], b = t.y + dy[i];
if(a < 1 || a > n || b < 1 || b > m) continue;
if(d[a][b] != -1) continue;
if(g[a][b] != 1) continue;
d[a][b] = d[t.x][t.y] + 1;
q.push({a, b});
if(a == x2 && b == y2) return d[x2][y2];
}
}
return -1;
}
int main()
{
// 请在此输入您的代码
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> g[i][j];
cin >> x1 >> y1 >> x2 >> y2;
cout << bfs();
return 0;
}
4.九宫重排(bfs最小步数模型)
【题目链接】九宫重排 - 蓝桥云课 (lanqiao.cn)
bfs最小步数模型——八数码变形题
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
map<string, int> d;
string start, ed;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int bfs()
{
queue<string> q;
d[start] = 0;
q.push(start);
while(q.size())
{
string t = q.front();
q.pop();
int distance = d[t];
if(t == ed) return d[ed];
int k = t.find(".");
int x = k / 3, y = k % 3;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if(a < 0 || a >= 3 || b < 0 || b >= 3) continue;
swap(t[k], t[a * 3 + b]);
if(!d.count(t))
{
d[t] = distance + 1;
q.push(t);
}
swap(t[k], t[a * 3 + b]);
}
}
return -1;
}
int main()
{
cin >> start;
cin >> ed;
cout << bfs();
return 0;
}
5.青蛙跳杯子(bfs最小步数模型)
【题目链接】青蛙跳杯子 - 蓝桥云课 (lanqiao.cn)
最小步数模型——八数码原题变形(同上)——,只是二维变成一维
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
map<string, int> d;
string start, ed;
int dx[6] = {-1, -2, -3, 1, 2, 3};
int len;
int bfs()
{
queue<string> q;
d[start] = 0;
q.push(start);
while(q.size())
{
string t = q.front();
q.pop();
int distance = d[t];
if(t == ed) return d[ed];
int k = t.find("*");
int x = k;
for (int i = 0; i < 6; i ++ )
{
int a = x + dx[i];
if(a < 0 || a > len) continue;
swap(t[k], t[a]);
if(!d.count(t))
{
d[t] = distance + 1;
q.push(t);
}
swap(t[k], t[a]);
}
}
return -1;
}
int main()
{
cin >> start;
cin >> ed;
len = start.size();
cout << bfs();
return 0;
}
6.最少操作数(最小步数模型)
【题目链接】
https://www.lanqiao.cn/problems/234/learning/)
三种操作,每种操作可以看做权值为一,然后求最短路(最小操作次数)。
与抓住那头牛一摸一样!
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, M = 2 * N;
int dist[N];
LL n, k;// 防止相乘时爆int直接LL
int bfs(int n, int k)
{
memset(dist, -1, sizeof dist);
queue<LL> q;
q.push(n);// 起点入队
dist[n] = 0;
while(q.size())
{
LL t = q.front();
q.pop();
if(t == k) return dist[t];
if(t + 1 < N && dist[t + 1] == -1)
{
dist[t + 1] = dist[t] + 1;
q.push(t + 1);
}
if(t - 1 > 0 && dist[t - 1] == -1)
{
dist[t - 1] = dist[t] + 1;
q.push(t - 1);
}
if(t * 2 < N && dist[t * 2] == -1)
{
dist[t * 2] = dist[t] + 1;
q.push(t * 2);
}
}
return -1;
}
int main()
{
cin >> n >> k;
cout << bfs(n, k) << endl;
return 0;
}
7.大胖子走迷宫(扩展型最短路模型)
【题目链接】大胖子走迷宫 - 蓝桥云课 (lanqiao.cn)
看了好些题解还不是很理解,先留着了QAQ
8.迷宫与陷阱(扩展型最短路模型)
【题目链接】迷宫与陷阱 - 蓝桥云课 (lanqiao.cn)
思路:BFS(拆点):
dist[x][y][k]
:从 [1, 1]
走到 [x, y]
这个点,还剩下 k
次无敌状态的最短距离;就要分情况考虑有无道具加持的状态!
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int N = 1010, M = 15;
char g[N][N];
int dist[N][N][M];
int n, k;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
struct Node
{
int x, y, k;
};
int bfs()
{
memset(dist, -1, sizeof dist);
queue<Node> q;
q.push({0, 0, 0});// 起点入队
dist[0][0][0] = 0;
while(q.size())
{
auto t = q.front();
q.pop();
if(t.x == n - 1 && t.y == n - 1) return dist[t.x][t.y][t.k];
for(int i = 0; i < 4; i ++)
{
int a = t.x + dx[i], b = t.y + dy[i];
if(a < 0 || a >= n || b < 0 || b >= n) continue;
if(g[a][b] == '#') continue;
// 获得道具
if(g[a][b] == '%' && dist[a][b][k] == -1)
{
q.push({a, b, k});
dist[a][b][k] = dist[t.x][t.y][t.k] + 1;
}
if(g[a][b] == 'X' && t.k != 0 && dist[a][b][t.k - 1] == -1)
{
q.push({a, b, t.k - 1});
dist[a][b][t.k - 1] = dist[t.x][t.y][t.k] + 1;
}
if(g[a][b] == '.' && t.k != 0 && dist[a][b][t.k - 1] == -1)
{
q.push({a, b, t.k - 1});
dist[a][b][t.k - 1] = dist[t.x][t.y][t.k] + 1;
}
// 未获得道具
if(g[a][b] == '.' && t.k == 0 && dist[a][b][0] == -1)// 再还没有获得道具时!!!
{
q.push({a, b, 0});
dist[a][b][0] = dist[t.x][t.y][t.k] + 1;
}
}
}
return -1;
}
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i ++ ) cin >> g[i];
cout << bfs() << endl;
return 0;
}