P1141 01迷宫

题目描述
有一个仅由数字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;
}

你可能感兴趣的:(浴谷)