【洛谷 P1141】01迷宫(记忆化BFS)

P1141 01迷宫
6.4K
通过
32.7K
提交
题目提供者
评测方式 云端评测
标签 高性能
难度 普及/提高-
时空限制 1000ms / 128MB

提示:收藏到任务计划后,可在首页查看。
最新讨论
推荐的相关题目
题目描述
有一个仅由数字00与11组成的n \times nn×n格迷宫。若你位于一格0上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格1上,那么你可以移动到相邻44格中的某一格00上。

你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

输入输出格式
输入格式:
第11行为两个正整数n,mn,m。

下面nn行,每行nn个字符,字符只可能是00或者11,字符之间没有空格。

接下来mm行,每行22个用空格分隔的正整数i,ji,j,对应了迷宫中第ii行第jj列的一个格子,询问从这一格开始能移动到多少格。

输出格式:
mm行,对于每个询问输出相应答案。

输入输出样例
输入样例#1:
2 2
01
10
1 1
2 2
输出样例#1:
4
4
说明
所有格子互相可达。

对于20\%20%的数据,n≤10n≤10;

对于40\%40%的数据,n≤50n≤50;

对于50\%50%的数据,m≤5m≤5;

对于60\%60%的数据,n≤100,m≤100n≤100,m≤100;

对于100\%100%的数据,n≤1000,m≤100000n≤1000,m≤100000。

刚开始直接对需要查询的点进行BFS,结果得了70分,有三个样例TLE了。
于是开始改进,我们想到:在同一个联通块内的答案是一样的,好,知道了
这一点就很简单了。我们再开一个栈/队列记录下来以 (i,j) ( i , j ) 为起点的联通块
路径,记忆化即可。然后我们只需要 BFS B F S 那些还没有答案的即可。
PS: P S : 栈和队列的定义最好在外面,否则可能会TLE,因为每次变量的重新
声明都需要时间。


#include<bits/stdc++.h>
using namespace std;
const int maxn =1550;
char maze[maxn][maxn];
bool vis[maxn][maxn];
int n,m;
struct node{
    int x,y;
};
bool check(int x,int y){
    return x>=0&&x<n&&y>=0&&y<n;
}
int dir[4][2]={-1,0,0,1,1,0,0,-1};
int num[maxn][maxn];
int ans;
node tn,rt;
stack<node> sta;
queue<node> que;
void bfs(int sx,int sy){
    ans=1;
    tn.x=sx;
    tn.y=sy;
    vis[tn.x][tn.y]=1;
    que.push(tn);
    while(!que.empty()){
        rt=que.front();
        que.pop();
        for(int i=0;i<4;i++){
            int dx=rt.x+dir[i][0];
            int dy=rt.y+dir[i][1];
            if(!vis[dx][dy]&&check(dx,dy)&&maze[dx][dy]!=maze[rt.x][rt.y]){
                vis[dx][dy]=1;
                tn.x=dx;
                tn.y=dy;
                ans++;
                que.push(tn);
                sta.push(tn);
            }
        }
    }
    num[sx][sy]=ans;
    while(!sta.empty()){
        num[sta.top().x][sta.top().y]=ans;
        sta.pop();
    }
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%s",maze[i]);
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(!vis[i][j]){
                bfs(i,j);
            }
        }
    }
    int tx,ty;
    while(m--){
        scanf("%d %d",&tx,&ty);
        printf("%d\n",num[tx-1][ty-1]);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值