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;
}
}