洛谷P1141 迷宫题解(典型的BFS)

题目描述

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

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

第1行为两个正整数n,m。

下面n行,每行n个字符,字符只可能是0或者1,字符之间没有空格。

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

输出格式:

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

输入输出样例
输入样例#1:

2 2
01
10
1 1
2 2

输出样例#1:

4
4

说明

所有格子互相可达。

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

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

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

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

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

思路:
本体就是BFS的模板题,有一点应该注意到就是连通的格子之间的答案是一样的,即求连通分量。在这里我们用fx[maxn][maxn]数组和fy[maxn][maxn]数组记录该格子的祖父(fx,fy),即该格子是从(fx,fy)通过BFS扩展来的,类似于并查集。ans[maxn][maxn]数组记录格子的答案。
住:这里要注意读入的问题,将在另一篇博客提到。
代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<string>
#include<map>
using namespace std;

int n, m;
const int maxn = 1005;
char mp[maxn][maxn];

int ans[maxn][maxn];
int dir[4][2] = { {1,0},{-1,0}, {0,1}, {0,-1} };
int vis[maxn][maxn];
int fx[maxn][maxn];
int fy[maxn][maxn];

struct p
{
	int x, y;
	p(int xx, int yy) {
		x = xx;
		y = yy;

	}
};

void bfs(int x, int y) {

	int cnt = 1; //题目里说明每个格子自己是可达的
	queue<p>q;
	q.push(p(x, y));
	vis[x][y] = 1;
	while (!q.empty()) {
		p f = q.front();
		q.pop();
		for (int i = 0; i < 4; i++) {
			int xx = f.x+dir[i][0];
			int yy = f.y +dir[i][1];
			
			if (xx > 0 && xx <=n&&yy > 0 && yy <= n&&!vis[xx][yy]) {
				if (mp[f.x][f.y] != mp[xx][yy]) { //0只能到1,1只能到0
					q.push(p(xx, yy));
					fx[xx][yy] = x;  //记录祖父的x坐标与y坐标
					fy[xx][yy] = y;
					vis[xx][yy] = 1;
					cnt++;
				}
			}
		}
	}
	ans[x][y] = cnt;  //x,y确定的格子可达的格子数

}

int main() {
	memset(ans, 0, sizeof ans);
	memset(vis, 0, sizeof vis);
	memset(fx, 0, sizeof fx);
	memset(fy, 0, sizeof fy);
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%s", mp[i] + 1);
	}


	for (int i = 1; i < m; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		if (ans[x][y])
			printf("%d\n", ans[x][y]);
		else {
			if (fx[x][y]) 
				ans[x][y] = ans[fx[x][y]][fy[x][y]];
			else
				bfs(x, y);		
			printf("%d\n", ans[x][y]);
		}
	
	}
	int x, y;
	scanf("%d %d", &x, &y);
	if (ans[x][y])  //如果已经求得答案,直接输出
		printf("%d", ans[x][y]);
	else {
		if (fx[x][y]) //如果该点是由其他节点扩展来的,因为在同一个连通分量里,所以答案跟祖父节点的答案相同
			ans[x][y] = ans[fx[x][y]][fy[x][y]];  
		else    //如果该点还没有被扩展,BFS
			bfs(x, y);
		printf("%d", ans[x][y]);
	}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值