洛谷 1141

P1141 01迷宫

题目描述

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

题目意思是求从某一点出发,向四个方向走,能走多少个格子。如果按照正常的广搜最后会超时。
超时代码:

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1200;
int vis[maxn][maxn];
char a[maxn][maxn];
int ans,n,m;
int dis[][2]= {-1,0,1,0,0,-1,0,1};
queue<int> que;
int bfs(int i,int j,int sum)
{
	int P;
	int col,row;
	que.push(i);
	que.push(j);
	que.push(a[i][j]-'0');
	vis[i][j]=1;
	while(!que.empty())
	{
		col=que.front();que.pop();
		row=que.front();que.pop();
		P=que.front();que.pop();
		for(int z=0; z<4; z++)
		{
			int dx=col+dis[z][0];
			int dy=row+dis[z][1];
			if(dx>=0&&dy>=0&&dx<n&&dy<n&&(a[dx][dy]-'0')!=P&&!vis[dx][dy])
			{
				que.push(dx);
				que.push(dy);
				que.push(a[dx][dy]-'0');
				vis[dx][dy]=1;
				sum++;
			}
		}
	}
	return sum;
}
int main()
{
	int x,y;
	cin>>n>>m;
	for(int k=0; k<n; k++)
		cin>>a[k];
	while(m--)
	{
		while(!que.empty())
			que.pop();
		memset(vis,0,sizeof(vis));
		cin>>x>>y;
		ans=bfs(x-1,y-1,1);
		cout<<ans<<endl;
	}
}

超时原因在于输入一组数据判断一组数据。所以要使用到连通块的思想,即当输入一组数据后,将该点能够到达的所有点标记,形成连通块,下次再输入数据时,如果该点已经在连通块内,直接输出即可。

AC代码:

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1200;
int vis[maxn][maxn],step[maxn][maxn];//vis数组标记该点是否访问过,step数组记录该点能够到达的所有点的格子
int in[1000001][3];//in数组记录当前能够到达的总格子的坐标
char a[maxn][maxn];
int ans,n,m;
int dis[][2]= {-1,0,1,0,0,-1,0,1};
queue<int> que;//que记录该点数据包括该点的坐标和数值(0/1),注意定义的是int型,所有该点的数值应该转换为int型。
int bfs(int i,int j)
{
	int P;
	int sum=1,flag=1;//flag与sum类似
	int col,row;
	que.push(i);
	que.push(j);
	que.push(a[i][j]-'0');//转换
	vis[i][j]=1;//将该点标记已访问★
	in[flag][0]=i;//记录下标
	in[flag][1]=j;
	while(!que.empty())
	{
		col=que.front();
		que.pop();
		row=que.front();
		que.pop();
		P=que.front();
		que.pop();
		for(int z=0; z<4; z++)
		{
			int dx=col+dis[z][0];
			int dy=row+dis[z][1];
			if(dx>=0&&dy>=0&&dx<n&&dy<n&&(a[dx][dy]-'0')!=P&&!vis[dx][dy])//注意dx,dy有时判断是否越界的条件不同★★
			{
				flag++;
				in[flag][0]=dx;
				in[flag][1]=dy;
				que.push(dx);
				que.push(dy);
				que.push(a[dx][dy]-'0');
				vis[dx][dy]=1;
				sum++;
			}
		}
	}
	for(int u=1; u<=flag; u++)
	{
		step[in[u][0]][in[u][1]]=sum;//如果该点在同一连通块内,它们到达的格子数目相同
	}
	return sum;
}
int main()
{
	int x,y;
	memset(vis,0,sizeof(vis));
	cin>>n>>m;
	for(int k=0; k<n; k++)
		cin>>a[k];
	while(m--)
	{
		cin>>x>>y;
		if(!vis[x-1][y-1])//搜索
		{
			bfs(x-1,y-1);
			cout<<step[x-1][y-1]<<endl;
		}
		else
			cout<<step[x-1][y-1]<<endl;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值