题目描述
有一个仅由数字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。
TJ:宽搜好题,
0 1
1 0
如果这里面一个位置都能到达其他位置,那么这个集合中任一位置都能到达其他位置。
0 — > 1
| |
v v
1 0
因为是0可以到达1,1也可以到达0,因此是双连通即:
0 — 1
| |
1 0
因此,只要求出连通块内有几个元素,那么这个集合中的所有格子能移动到多少个格子的数量都是几。
问题是如何求连通块内有几个元素呢?实际上就是宽搜的尾指针数。想一想为什么?
然后类似于记忆化搜索,标记一下是否走过,走过的放进表里(布尔数组),搜索的时候先查询,没有再搜索。搜索的时候先记录,再返回。
代码如下:注意数组大小,否则MLE
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,t,b[1005][1005],c[1005][1005],ax[1000000],ay[1000000],mk[1000000],x,y,ans[1005][1005];
char a[1005][1005];
int mx[4]={0,0,1,-1},
my[4]={1,-1,0,0};
void bfs(int x,int y)
{
int head=1,tail=1;
ax[1]=x,ay[1]=y,b[x][y]=1;//b[]忘写了
while(head<=tail)//这样写规范,也亦理解,循环体里面的tail 是几就表示进行到几了。
{
for(int i=0;i<4;i++)
{
int xx=ax[head]+mx[i];
int yy=ay[head]+my[i];
if(xx>=1 && xx<=n && yy>=1 && yy<=n && c[xx][yy]!=c[ax[head]][ay[head]] && !b[xx][yy])
{
tail++;
ax[tail]=xx;
ay[tail]=yy;
b[xx][yy]=1;
}
}
head++;
}
for(int i=1;i<=tail;i++) ans[ax[i]][ay[i]]=tail;
}
int main()
{
scanf("%d%d",&n,&t);
for(int i=1;i<=n;i++)
{
scanf("%s",a[i]+1);
for(int j=1;j<=n;j++)
c[i][j]=a[i][j]-'0';
}
for(int i=1;i<=t;i++)
{
scanf("%d%d",&x,&y);
if(!b[x][y]) bfs(x,y);
cout<<ans[x][y]<<endl;
}
}
看下面读入的方法scanf(“%1d”,&a[i][j])
#include<iostream>
#include<cstdio>
using namespace std;
int fx[5]={0,0,1,0,-1},fy[5]={0,1,0,-1,0},n,m,a[1001][1001],ans[1001][1001],mgx[1000001],mgy[1000001],x,y; //数组啥的开大点,防爆(炸)嘛。
bool b[1001][1001];
void bfs(int x,int y)
{
int h=0,t=1,tx,ty;b[x][y]=1,mgx[h]=x,mgy[h]=y; //头标尾标啥的赋初值。mgx[h]可改成mgx[0]都一样。(说明一下,mgx和mgy是广搜用的队列。)
while(h<t) //do-while和while应该都可以。
{
for(int i=1;i<=4;i++) //四向搜索。
{
tx=mgx[h]+fx[i],ty=mgy[h]+fy[i]; //tx/ty,用来判断下一步。
if((tx>=1&&tx<=n)&&(ty>=1&&ty<=n)&&(a[tx][ty]!=a[mgx[h]][mgy[h]])&&(!b[tx][ty]))mgx[t]=tx,mgy[t]=ty,b[tx][ty]=1,t++; //没有超界并且达到此点不等于下点的值并且没走过此点则存入队列。
}
h++;
}
for(int i=0;i<t;i++)ans[mgx[i]][mgy[i]]=t;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%1d",&a[i][j]); //读入,也可用字符读入。
for(int i=1;i<=m;i++)
{
cin>>x>>y; //读入起始点。
if(!b[x][y])bfs(x,y);
cout<<ans[x][y]<<endl; //输出答案。
}
}