@Moritz
2019-04-07T11:43:58.000000Z
字数 2397
阅读 461
洛谷
DFS
优化
C++
所有文稿
有一个仅由数字与组成的格迷宫。若你位于一格上,那么你可以移动到相邻格中的某一格上,同样若你位于一格上,那么你可以移动到相邻格中的某一格上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入格式:
第行为两个正整数。
下面行,每行个字符,字符只可能是或者,字符之间没有空格。
接下来行,每行个用空格分隔的正整数,对应了迷宫中第行第列的一个格子,询问从这一格开始能移动到多少格。
输出格式:
行,对于每个询问输出相应答案。
输入样例
2 2
01
10
1 1
2 2
输出样例
4
4
所有格子互相可达。
对于的数据,;
对于的数据,;
对于的数据,;
对于的数据,;
对于的数据,。
主要注意的是一个优化问题
一开始用BFS写,其实本质上是求连通块,所以两种算法都可以,但是都遇到了有三个测试点超时的问题
#include <iostream>
#include <cmath>
#include <string>
#include <string.h>
#include <queue>
using namespace std;
int n,m,cnt=0;
bool t[1010][1010],step[1010][1010];
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
void dfs(int x,int y){
for(int j=0;j<4;j++) {
int yy=y+dir[j][0],xx=x+dir[j][1];
if (yy>0&&yy<=n&&xx>0&&xx<=n){
if (t[y][x]!=t[yy][xx]&&step[yy][xx]){
cnt++;
step[yy][xx]=false;
dfs(xx,yy);
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char c;
cin>>c;
if (c=='1') t[i][j]=true;
else t[i][j]=false;
}
}
for(int i=0;i<m;i++){
memset(step,true,sizeof(step));
cnt=1;//包括起点在内
int x1,y1;
cin>>y1>>x1;
step[y1][x1]=false;//注意起点的标记
queue<pair<int,int> > qu;
qu.push(make_pair(x1,y1));
while(!qu.empty()){//bfs
int x=qu.front().first,y=qu.front().second;
qu.pop();
for(int j=0;j<4;j++) {
int yy=y+dir[j][0],xx=x+dir[j][1];
if (yy>0&&yy<=n&&xx>0&&xx<=n){
if (t[y][x]!=t[yy][xx]&&step[yy][xx]){
cnt++;
step[yy][xx]=false;
qu.push(make_pair(xx,yy));
}
}
}
}
cout<<cnt<<endl;
}
return 0;
}
在深搜的过程中加入了已搜索的标记
#include <iostream>
#include <cmath>
#include <string>
#include <string.h>
#include <cstdio>
using namespace std;
int n,m,cnt=1;
bool t[1010][1010],step[1010][1010];
int a[1010][1010];//序号记录
int ma[1000010];//序号为in的连通块,连通块数量为ma[in]
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
void dfs(int x,int y,int num){
for(int j=0;j<4;j++) {
int yy=y+dir[j][0],xx=x+dir[j][1];
if (yy>0&&yy<=n&&xx>0&&xx<=n){
if (t[y][x]!=t[yy][xx]&&step[yy][xx]){
cnt++;
step[yy][xx]=false;
a[yy][xx]=num;//标记序号
dfs(xx,yy,num);
}
}
}
}
int main(){
memset(a,-1,sizeof(a));
memset(step,true,sizeof(step));
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char c;
cin>>c;
if (c=='1') t[i][j]=true;
else t[i][j]=false;
}
}
for(int i=0;i<m;i++){
cnt=1;//包括起点在内
int x1,y1;
scanf("%d%d",&y1,&x1);
if (a[y1][x1]>0) printf("%d\n",ma[(a[y1][x1])]);
else{
step[y1][x1]=false;//注意起点的标记
a[y1][x1]=i+1;
dfs(x1,y1,i+1);
ma[i+1]=cnt;
/*
这是之前的一个做法,直接在序号标记数组里记录连通块数量,但还是超时,所以改成了标号,根据标号查找联通量
for(int in=1;in<=n;in++){
for(int jn=1;jn<=n;jn++){
if (!step[in][jn]) a[in][jn]=cnt;
}
}
*/
printf("%d\n",cnt);
}
}
return 0;
}