【蓝桥杯】BFS专题


BFS专题

题库:在线题库_在线做题_智能评测_蓝桥云课题库 - 蓝桥云课 (lanqiao.cn)

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)

这里再附上一道题同类目:

链接:多源BFS_塔塔开!!!的博客-CSDN博客

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;
}
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值