bfs见解和基本模板:最短距离和路径

BFS使用队列辅助求解

在使用bfs求解问题前,我们应该至少考虑三个问题:

  1. 将每个结点作为一种状态,用什么数据结构来记录这种状态
  2. 用该状态该怎么扩展节点,该节点可以怎样被扩展,要注意边界控制
  3. 在队列中以什么标准优先扩展,必要时使用优先队列

这三个问题使用下面这个基本迷宫问题回答:

  1. Node n(x, y);
  2. 迷宫问题 可以上 下 左 右 四个方向移动。
  3. 距离短优先,当然会有权值小优先等等。

还有一个问题,我在一道题中遇到的:下面bfs中的vis[u.x][u.y] = 1到底放在哪?

void bfs(int m, int n) {
    queue<Node> que;
    que.push(Node(0, 0));
    while(!que.empty()) {
        Node u = que.front(); que.pop();
        if(u.x==m-1 && u.y==n-1) return;
        for(int i = 0; i < 4; i++) {
            int x_t = u.x + dir_x[i];
            int y_t = u.y + dir_y[i];
            if(matrix[x_t][y_t] && !vis[x_t][y_t] && (x_t>=0 && y_t>=0 && x_t<m && y_t<n)){
                // 父结点x,y坐标合并成一个数
                fath[x_t][y_t] = u.x*100+u.y;
                dis[x_t][y_t] = dis[u.x][u.y] + 1;
                vis[u.x][u.y] = 1;
                que.push(Node(x_t, y_t));
            }
        }
    }
}

我之前都是习惯放在判定中的,即 判定允许移动到该节点后,便把该节点标记为有1,暗指其他节点遍历不到该点了。(尽管该点还没有遍历到)。

但前几天遇到了一道题便错了,这道题的内容要求 判定过允许到一个节点,但是不能标记该点,因为其他节点遍历时再遍历该点可能会有更优解。题目链接:https://vjudge.net/problem/UVA-1600

然后便发现,(对于普遍的bfs题目)使用前者效率更高,后者会重复遍历节点,看情况使用。有的题卡时间紧,后者就超时了(前几天便遇见了)。

 

最短距离使用dis二维数组,路径使用fath二维数组,还用使用vis进行是否访问判断。

输入

4 6
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1

输出

长为:8
0 0
1 0
2 0
3 0
3 1
3 2
3 3
3 4
3 5

#include <iostream>
#include <cstdio>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include <cstring>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
using namespace std;
const int maxn = 20;
int matrix[maxn][maxn], vis[maxn][maxn];
// 距离 和 父结点
int dis[maxn][maxn], fath[maxn][maxn];

int dir_x[4] = {0, 0, -1, 1};
int dir_y[4] = {1, -1, 0, 0};

struct Node {
    int x, y;
    Node(int _x, int _y):
        x(_x), y(_y) {}
};

void bfs(int m, int n) {
    queue<Node> que;
    que.push(Node(0, 0));
    while(!que.empty()) {
        Node u = que.front(); que.pop();
        if(u.x==m-1 && u.y==n-1) return;
        for(int i = 0; i < 4; i++) {
            int x_t = u.x + dir_x[i];
            int y_t = u.y + dir_y[i];
            if(matrix[x_t][y_t] && !vis[x_t][y_t] && (x_t>=0 && y_t>=0 && x_t<m && y_t<n)) {
                // 父结点x,y坐标合并成一个数
                fath[x_t][y_t] = u.x*100+u.y;
                dis[x_t][y_t] = dis[u.x][u.y] + 1;
                vis[u.x][u.y] = 1;
                que.push(Node(x_t, y_t));
            }
        }
    }
}

int main() {
    freopen("i.txt", "r", stdin);   
    // freopen("o.txt", "w", stdout);   
    int m, n;
    cin >> m >> n;
    memset(matrix, 0, sizeof(matrix));
    memset(vis, 0, sizeof(matrix));
    memset(dis, 0, sizeof(dis));
    memset(fath, 0, sizeof(fath));
    for(int i = 0; i < m; i++) {
        for(int j = 0; j < n; j++) {
            cin >> matrix[i][j];
        }
    }
    bfs(m, n);
    cout << "长为:" << dis[m-1][n-1] << endl;

    // 将路径存入栈
    stack<Node> res;
    int x = m-1, y = n-1;
    while(true) {
        res.push(Node(x, y));
        if(!x && !y) break;
        int num = fath[x][y];
        // 父结点分离
        x = num/100;
        y = num%100;
    }

    while(!res.empty()) {
        Node u = res.top();
        res.pop();
        cout << u.x << " " << u.y << endl;
    }

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值