BFS(广度优先搜索)记忆搜索(三)

  一提到BFS的时候大家一般都会申请一个数组vis,vis的作用是用来标记有没有搜索过,如果搜索过那么vis = 1,如果没有搜索过那么vis = 0,在每一次搜索的时候都会重新初始化vis, 把vis初始化为0,如果查询的次数比较多,那么就白白浪费了很多时间,很多的操作其实都是重复的,所以这篇博客讲述BFS+记忆搜索。

  大家在做BFS题的时候有没有意识到其实BFS在搜索的时候只是搜索连通的某块,就比如说你在一个荒岛上,其他人在另外一个岛上,你和其他人也没有办法取得联系,所以BFS的搜索也是一个道题,BFS模块搜索的其实只是互相连通模块,如果不互相连通那么这些模块其实没有任何关系,也就是不能相互到达。所以在记忆化搜索时vis就不用每次初始化,一次就行,vis用来记录可以相互到达的模块。在每次查询的时候只要先询问是否被分配到一个模块中,如果没有在就用BFS查询,如果有直接就知道这个模块的中几个点可以相互到达。

01迷宫     洛谷     P1141

连接:https://www.luogu.org/problemnew/show/P1141

题意:有一个仅由数字00与11组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格1上,那么你可以移动到相邻44格中的某一格00上。你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

题解:题意很简单,但是查询的次数比较多,如果只用最普通的查询那么这道题会直接TLE的,一开始我就直接普通的BFS算法,但是只通过了70%,其中有三个直接TLE,有三个点的数据太大,不适合直接查询,所以需要BFS+记忆化,只要某些点在同一个某块中这些点就可以相互到达。

这个是一开始大代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
#define N 1005
struct Node{
       int x, y;
       char pre;
}tmp1, tmp2;
char a[N][N];
int n, step;
int dx[8]={1,-1,0,0};
int dy[8]={0,0,1,-1,};
int vis[N][N];
void bfs(int st, int en){
     memset(vis, 0, sizeof(vis));
     step = 0;
     tmp1.x = st;
     tmp1.y = en;
     vis[st][en]= 1;
     tmp1.pre = a[st][en];
     queue<Node>q;
     q.push(tmp1);
     while(!q.empty()){
        tmp1 = q.front();
        q.pop();
        //cout<<tmp1.x<<" "<<tmp1.y<<endl;
        for(int i = 0; i < 8; i++){
            tmp2.x = tmp1.x + dx[i];
            tmp2.y = tmp1.y + dy[i];
            if(tmp2.x >= 0 && tmp2.x<n && tmp2.y>= 0&&tmp2.y < n && !vis[tmp2.x][tmp2.y]&& a[tmp2.x][tmp2.y]!=tmp1.pre){
                vis[tmp2.x][tmp2.y] = 1;
                tmp2.pre = a[tmp2.x][tmp2.y];
                q.push(tmp2);
                step++;
            }
        }
     }
}
int main(){
    int m, st, en;
    cin>>n>>m;
    for(int i = 0; i < n; i++){
        scanf("%s", a[i]);
    }
    while(m--){
        cin>>st>>en;
        bfs(st-1, en-1);
        cout<<step+1<<endl;
    }
return 0;
}

这个是AC代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
#define N 1005
#define maxn 1000005
struct Node
{
    int x, y;
    char pre;
} tmp1, tmp2;
char a[N][N];
int n, num = 0;
int dx[8]= {1,-1,0,0};
int dy[8]= {0,0,1,-1,};
int vis[N][N];
int ans[maxn];
int bfs(int st, int en)
{
    num++;
    int step = 1;
    tmp1.x = st;
    tmp1.y = en;
    vis[st][en]= num;
    tmp1.pre = a[st][en];
    queue<Node>q;
    q.push(tmp1);
    while(!q.empty())
    {
        tmp1 = q.front();
        q.pop();
        for(int i = 0; i < 8; i++)
        {
            tmp2.x = tmp1.x + dx[i];
            tmp2.y = tmp1.y + dy[i];
            if(tmp2.x >= 0 && tmp2.x<n && tmp2.y>= 0&&tmp2.y < n && !vis[tmp2.x][tmp2.y]&& a[tmp2.x][tmp2.y]!=tmp1.pre)
            {
                vis[tmp2.x][tmp2.y] = num;
                tmp2.pre = a[tmp2.x][tmp2.y];
                q.push(tmp2);
                step++;
            }
        }
    }
    ans[num] = step;
    return step;
}
int main()
{
    int m, st, en;
    cin>>n>>m;
    for(int i = 0; i < n; i++)
    {
        scanf("%s", a[i]);
    }
    while(m--)
    {
        cin>>st>>en;
        if(!vis[st-1][en-1])//查询是否在一个模块中
            cout<<bfs(st-1, en-1)<<endl;
        else cout<<ans[vis[st-1][en-1]]<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值