题目描述
有一个仅由数字00与11组成的n \times nn×n格迷宫。若你位于一格0上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格1上,那么你可以移动到相邻44格中的某一格00上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入输出格式
输入格式:
第11行为两个正整数n,mn,m。
下面nn行,每行nn个字符,字符只可能是00或者11,字符之间没有空格。
接下来mm行,每行22个用空格分隔的正整数i,ji,j,对应了迷宫中第ii行第jj列的一个格子,询问从这一格开始能移动到多少格。
输出格式:
mm行,对于每个询问输出相应答案。
输入输出样例
输入样例#1:
2 2
01
10
1 1
2 2
输出样例#1:
4
4
说明
所有格子互相可达。
对于20%20%的数据,n≤10n≤10;
对于40%40%的数据,n≤50n≤50;
对于50%50%的数据,m≤5m≤5;
对于60%60%的数据,n≤100,m≤100n≤100,m≤100;
对于100%100%的数据,n≤1000,m≤100000n≤1000,m≤100000。
这道题我先是自己写的,超时,这是我第一次写的。
m次,每一次都要遍历一遍。将遍历过的vi[i][j]赋值为1,然后再统计1的个数。
#include
using namespace std;
int n,m;
int vi[1005][1005];
int a[1005][1005];
int bfs(int a[][1005],int x,int y,int k)
{
if(vi[x][y] == 1){
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
printf("%d\n",vi[i][j]);
}
printf("\n");
}
return 0;
}
if(a[x][y] == 2) vi[x][y] = 1;
int vis[4][2]={1,0,-1,0,0,1,0,-1};
for(int i = 0;i < 4;i++){
int e = x+vis[i][0];
int f = y+vis[i][1];
if(e>=1&&e<=n&&f>=1&&f<=n&&a[e][f]==k){
int p = (a[e][f]+1)%2;
a[e][f] = 2;
bfs(a,e,f,p);
a[e][f] = (p+1)%2;
}
}
}
int print()
{
int ans = 0;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
if(vi[i][j] == 1) ans++;
// printf("%d",vi[i][j]);
}
// printf("\n");
}
return ans;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
scanf("%1d",&a[i][j]);
}
}
while(m--){
int x,y;
memset(vi,0,sizeof(vi));
scanf("%d %d",&x,&y);
int k = (a[x][y]+1)%2;
int t = a[x][y];
a[x][y] = 2;
bfs(a,x,y,k);
a[x][y] = t;
int ans = print();
printf("%d\n",ans);
}
return 0;
}
这是看了题解写的。
0可以找到1,1可以找到0,那么这些相连的所走的格树肯定都一样多,只要统计一个连通块的个数,然后再赋值给这个连通块所有的格数,
我是(O(n*m)这样赋值的,所以又超时了
#include
using namespace std;
int n,m;
int vi[1005][1005];
int a[1005][1005];
int bfs(int x,int y,int t)
{
if(vi[x][y] == t) return 0;
vi[x][y] = t;
int vis[4][2]={1,0,-1,0,0,1,0,-1};
for(int i = 0;i < 4;i++){
int e = x+vis[i][0];
int f = y+vis[i][1];
if(e>=1&&e<=n&&f>=1&&f<=n){
if(a[e][f] == (a[x][y]+1)%2){
bfs(e,f,t);
}
}
}
}
int print(int k)
{
int ans = 0;
for(int i = 1;i <= n;i++){
for(int j =1;j <= n;j++)
if(vi[i][j] == k) ans++;
}
return ans;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
scanf("%1d",&a[i][j]);
}
}
int t = 1;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
if(vi[i][j] == 0){
bfs(i,j,t);
t++;
}
}
}
while(m--){
int x,y;
scanf("%d %d",&x,&y);
int k = vi[x][y];
int ans = print(k);
printf("%d\n",ans);
}
/*
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
printf("%d",vi[i][j]);
}
printf("\n");
}
*/
return 0;
}
其实只需要将所有遍历过的格数的下标记录下来,然后再赋值就可以了。
#include
using namespace std;
int n,m;
int len = 0;
int vi[1005][1005];
int a[1005][1005];
int h[1000005][2];
int bfs(int x,int y,int t,int h[][2])
{
if(vi[x][y] == t) return 0;
vi[x][y] = t;
h[len][0] = x;
h[len++][1] = y;
int vis[4][2]={1,0,-1,0,0,1,0,-1};
for(int i = 0;i < 4;i++){
int e = x+vis[i][0];
int f = y+vis[i][1];
if(e>=1&&e<=n&&f>=1&&f<=n){
if(a[e][f] == (a[x][y]+1)%2){
bfs(e,f,t,h);
}
}
}
}
int swap(int len)
{
for(int i = 0;i < len;i++){
vi[h[i][0]][h[i][1]] = len;
}
return 0;
}
int main()
{
scanf("%d %d",&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 <= n;i++){
for(int j = 1;j <= n;j++){
if(vi[i][j] == 0){
len = 0;
bfs(i,j,-1,h);
swap(len);
}
}
}
while(m--){
int x,y;
scanf("%d %d",&x,&y);
printf("%d\n",vi[x][y]);
}
return 0;
}