洛谷P1141 01迷宫

题目描述

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

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

输入格式:

第 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

所有格子互相可达。

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

明显数据量十分大,如果常规BFS每读入一个坐标就在迷宫中查一遍的会TEL,那么需要进行优化预处理,筛选一次,在此基础上查询多次:开始从(1,1)出发对迷宫只查一遍,将所有连通的格子标记为一个连通块(BFS求连通块),记录其对应的数目。查询时输入坐标看其在哪一个连通块中,输出该连通块对应的数目,大大降低了查找时间。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
using namespace std; 
int n, m;
char map[1001][1001];
int vis[1001][1001];          //记录该坐标属于哪一个连通块
int dx[4] = { 0,1,0,-1 }, dy[4] = { 1,0,-1,0 };
int a[1000001];               //记录连通块所包含的数目
struct point
{
	int x;
	int y;
}tmp1,tmp2;
int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			cin >> map[i][j];
	int d = 1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (vis[i][j] == 0)          //如果该点还不属于任何一个连通块,那么以它为起点查找这个连通块
			{
				queue<point> q;
				int ans = 1;
				tmp1.x = i; tmp1.y = j; vis[i][j] = d; q.push(tmp1);
				while (!q.empty())       //常规BFS,利用队列压入点
				{
					tmp1 = q.front(); q.pop();
					int flag = map[tmp1.x][tmp1.y] - '0';
					for (int k = 0; k < 4; k++)
					{
						tmp2.x = tmp1.x + dx[k]; tmp2.y = tmp1.y + dy[k];
						if (tmp2.x >= 1 && tmp2.x <= n&&tmp2.y >= 1 && tmp2.y <= n&&vis[tmp2.x][tmp2.y] == 0 && map[tmp2.x][tmp2.y] - '0' == !flag)
						{
							vis[tmp2.x][tmp2.y] = d;   //能够达到则标记这个点在该连通块中,数目加1
							ans++;
							q.push(tmp2);
						}
					}
				}
				a[d] = ans; d++;         //记录这个连通块的数目个数,连通块数加1
			}
		}
	}
	while (m--)                          //查询操作
	{
		int x, y;
		cin >> x >> y;
		cout << a[vis[x][y]] << endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/slience_646898/article/details/81202959
今日推荐