洛谷--P1141 01迷宫(预处理BFS)

文章描述了一个用01矩阵表示的n×n迷宫问题,其中0和1分别代表不同状态的格子,玩家可以从0移动到1或从1移动到0。任务是计算从特定起点可以到达的格子总数(含起点)。为避免超时,文章提出预处理每个点可达格子数并使用BFS进行联通块的遍历。给出的C++代码实现了一个基于BFS的解决方案,用于计算每个点的可达范围并在询问时直接输出结果。
摘要由CSDN通过智能技术生成

题目描述

有一个仅由数字 0 与 1 组成的 n×n 格迷宫。若你位于一格 0 上,那么你可以移动到相邻 4 格中的某一格 1 上,同样若你位于一格 1 上,那么你可以移动到相邻 4 格中的某一格 0 上。

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

输入格式

有一个仅由数字 0 与 1 组成的 n×n 格迷宫。若你位于一格 0 上,那么你可以移动到相邻 4 格中的某一格 1 上,同样若你位于一格1 上,那么你可以移动到相邻 4 格中的某一格 0 上。

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

输出格式

m 行,对于每个询问输出相应答案。

输入样例

2 2
01
10
1 1
2 2

输出样例

4
4

 说明

所有格子互相可达,对于 100% 的数据 n≤1000,m≤100000。

解析:如果对于每个询问的坐标进行bfs,那么就会超时了,对于一个点(x1,y1)能到的点(x2,y2),那么(x2,y2)也可以到(x1,y1),因此他们对于最多能走几个方格的答案值是相同的,因此我们可以预处理每个点的答案,对于每一组询问直接输出即可。

小方法:从(x,y)开始bfs,同时记录下他能到的所有点(数组队列什么都行🙃),然后对于这个联通块,答案都是相同的,结束的时候赋值dist[ ][ ]记录下答案即可。

#include <bits/stdc++.h>
using namespace std;
const int N=1005;
typedef pair<int,int> PII;
int a[N][N],dist[N][N],n,m;
bool st[N][N];
void bfs(int x,int y)
{
	int cnt=1;
	queue<PII> path;//保存记录(x,y)能到的所有点
	queue<PII> q;
	st[x][y]=true;
	int dx[4]={0,0,1,-1};
	int dy[4]={1,-1,0,0};
	q.push({x,y});
	path.push({x,y});//包括自身
	while(q.size())
	{
		int x1=q.front().first;
		int y1=q.front().second;
		q.pop();
		for(int i=0;i<4;i++)
		{
			int x2=x1+dx[i];
			int y2=y1+dy[i];
			if(!(x2>=1&&x2<=n&&y2>=1&&y2<=n)) continue;//越界
			if((a[x2][y2]!=a[x1][y1])&&!st[x2][y2])
			{
				cnt++;
				q.push({x2,y2});
				path.push({x2,y2});//保存
				st[x2][y2]=true;//标记访问
			}
		}
	}
	while(path.size())//对于这个联通块,赋值答案
	{
		int x=path.front().first;
		int y=path.front().second;
		path.pop();
		dist[x][y]=cnt;
	}
}
void solve()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) scanf(" %c",&a[i][j]);//输入迷宫
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) if(!st[i][j]) bfs(i,j);//如果没访问过
	while(m--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\n",dist[x][y]);
	}
}
int main()
{
	solve();
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值