解题报告 P1141 【01迷宫】广度优先搜索

wjyyy

2018-03-11 20:21:16

Solution

迷宫这个模型各位OIer见得可多了,一般是搜索类题目,同样地,这道题是一道~~**巨坑**~~浅显的广搜题 我们直接看判断条件:在当前点可以走到相邻的不同数字的点上去 这个题有多个询问,并且$m\le100,000$,所以每次做一遍BFS肯定不现实(事实证明这样还是有$70$分的),所以要用到记忆化搜索,这样才能减少时间开销。 记忆化搜索思想:已经搜到的联通块不必再搜,将处于相同联通块的格子用并查集并起来,即在之后的搜索中,一旦搜索到与当前状态的格子处于相同联通块的格子,则直接跳过,则一个联通块只会搜到一次。那么当一个点更新完时,与它相连的联通块的值(可以到达的点)一定和它一样,用vis数组存下来,这样可以用vis数组代替bool数组used(我的最初程序也用到了used,后来发现不需要,不知道bool数组调用时会不会稍微快一点),因此在之后vis不为0的点就不需要入队了。 #### 说到used数组,有一个重要的点希望大家不要被坑了 就是不要在每次的bfs里都对used数组重置一遍,第一很费时间,第二,完全没有必要,第三,想打裸的BFS($70$分)用used是需要每次重置的,因为每次相当于重新做了一遍,没有用到记忆化 **另一个注意事项**:在相邻格子遍历时,千万不要越界,所以大家看到我的判断条件比较长**~~(其实一个for循环解决一切)~~**,多一个条件保险一些。 **再一个注意事项**,这个题的输入格式是字符形式,所以要考虑行末有没有'\n'(用cin当我没说,其实也可以过)要特意读入一下 剩下的就是考广搜的基本功啦 ------------ # Code: ```cpp #include<cstring> #include<cstdio> #include<queue> using namespace std; struct point { int x,y; }t[1000005]; queue<point> q; int a[1001][1001],vis[1001][1001],s[1000005]; int n,m,u[1001][1001]; int Find(int x) { if(s[x]==x) return s[x]; return s[x]=Find(s[x]); } void Union(int x,int y) { s[Find(y)]=s[Find(x)]; return ; } void turn(int x)//预处理坐标转换(用空间换时间) { for(int i=1;i<=x;i++) for(int j=1;j<=x;j++) u[i][j]=(i-1)*n+j; return; } int bfs(int x,int y) { int ans=0,k=0; point p; p.x=x; p.y=y; q.push(p); while(!q.empty()) { p=q.front(); q.pop(); t[++k].x=p.x; t[k].y=p.y; if(vis[p.x][p.y]) { ans+=vis[p.x][p.y]; continue; } ans++; if(!vis[p.x-1][p.y]&&p.x>1&&a[p.x-1][p.y]!=a[p.x][p.y]) if(Find(u[p.x-1][p.y])!=Find(u[p.x][p.y])) { p.x--; q.push(p); p.x++; Union(u[p.x-1][p.y],u[p.x][p.y]); } if(!vis[p.x+1][p.y]&&p.x<n&&a[p.x+1][p.y]!=a[p.x][p.y]) if(Find(u[p.x+1][p.y])!=Find(u[p.x][p.y])) { p.x++; q.push(p); p.x--; Union(u[p.x+1][p.y],u[p.x][p.y]); } if(!vis[p.x][p.y-1]&&p.y>1&&a[p.x][p.y-1]!=a[p.x][p.y]) if(Find(u[p.x][p.y-1])!=Find(u[p.x][p.y])) { p.y--; q.push(p); p.y++; Union(u[p.x][p.y-1],u[p.x][p.y]); } if(!vis[p.x][p.y+1]&&p.y<n&&a[p.x][p.y+1]!=a[p.x][p.y]) if(Find(u[p.x][p.y+1])!=Find(u[p.x][p.y])) { p.y++; q.push(p); p.y--; Union(u[p.x][p.y+1],u[p.x][p.y]); } } for(int i=1;i<=k;i++) vis[t[i].x][t[i].y]=ans; vis[x][y]=ans; return ans; } int main() { memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&m); for(int i=1;i<=n*n;i++) s[i]=i; turn(n); char c; scanf("\n"); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { c=getchar(); a[i][j]=c-'0'; } scanf("\n"); } int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); printf("%d\n",bfs(x,y)); } return 0; } ```