[关闭]
@Moritz 2019-04-07T11:43:58.000000Z 字数 2397 阅读 461

P1141 01迷宫

洛谷 DFS 优化 C++ 所有文稿


题目描述

有一个仅由数字组成的格迷宫。若你位于一格上,那么你可以移动到相邻格中的某一格上,同样若你位于一格上,那么你可以移动到相邻格中的某一格上。

你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

输入输出格式

输入格式:

行为两个正整数

下面行,每行个字符,字符只可能是或者,字符之间没有空格。

接下来行,每行个用空格分隔的正整数,对应了迷宫中第行第列的一个格子,询问从这一格开始能移动到多少格。

输出格式:

行,对于每个询问输出相应答案。

输入输出样例

输入样例

  1. 2 2
  2. 01
  3. 10
  4. 1 1
  5. 2 2

输出样例

  1. 4
  2. 4

说明

所有格子互相可达。

对于的数据,

对于的数据,

对于的数据,

对于的数据,

对于的数据,

主要注意的是一个优化问题

一开始用BFS写,其实本质上是求连通块,所以两种算法都可以,但是都遇到了有三个测试点超时的问题

  1. #include <iostream>
  2. #include <cmath>
  3. #include <string>
  4. #include <string.h>
  5. #include <queue>
  6. using namespace std;
  7. int n,m,cnt=0;
  8. bool t[1010][1010],step[1010][1010];
  9. int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
  10. void dfs(int x,int y){
  11. for(int j=0;j<4;j++) {
  12. int yy=y+dir[j][0],xx=x+dir[j][1];
  13. if (yy>0&&yy<=n&&xx>0&&xx<=n){
  14. if (t[y][x]!=t[yy][xx]&&step[yy][xx]){
  15. cnt++;
  16. step[yy][xx]=false;
  17. dfs(xx,yy);
  18. }
  19. }
  20. }
  21. }
  22. int main(){
  23. cin>>n>>m;
  24. for(int i=1;i<=n;i++){
  25. for(int j=1;j<=n;j++){
  26. char c;
  27. cin>>c;
  28. if (c=='1') t[i][j]=true;
  29. else t[i][j]=false;
  30. }
  31. }
  32. for(int i=0;i<m;i++){
  33. memset(step,true,sizeof(step));
  34. cnt=1;//包括起点在内
  35. int x1,y1;
  36. cin>>y1>>x1;
  37. step[y1][x1]=false;//注意起点的标记
  38. queue<pair<int,int> > qu;
  39. qu.push(make_pair(x1,y1));
  40. while(!qu.empty()){//bfs
  41. int x=qu.front().first,y=qu.front().second;
  42. qu.pop();
  43. for(int j=0;j<4;j++) {
  44. int yy=y+dir[j][0],xx=x+dir[j][1];
  45. if (yy>0&&yy<=n&&xx>0&&xx<=n){
  46. if (t[y][x]!=t[yy][xx]&&step[yy][xx]){
  47. cnt++;
  48. step[yy][xx]=false;
  49. qu.push(make_pair(xx,yy));
  50. }
  51. }
  52. }
  53. }
  54. cout<<cnt<<endl;
  55. }
  56. return 0;
  57. }

在深搜的过程中加入了已搜索的标记

  1. #include <iostream>
  2. #include <cmath>
  3. #include <string>
  4. #include <string.h>
  5. #include <cstdio>
  6. using namespace std;
  7. int n,m,cnt=1;
  8. bool t[1010][1010],step[1010][1010];
  9. int a[1010][1010];//序号记录
  10. int ma[1000010];//序号为in的连通块,连通块数量为ma[in]
  11. int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
  12. void dfs(int x,int y,int num){
  13. for(int j=0;j<4;j++) {
  14. int yy=y+dir[j][0],xx=x+dir[j][1];
  15. if (yy>0&&yy<=n&&xx>0&&xx<=n){
  16. if (t[y][x]!=t[yy][xx]&&step[yy][xx]){
  17. cnt++;
  18. step[yy][xx]=false;
  19. a[yy][xx]=num;//标记序号
  20. dfs(xx,yy,num);
  21. }
  22. }
  23. }
  24. }
  25. int main(){
  26. memset(a,-1,sizeof(a));
  27. memset(step,true,sizeof(step));
  28. cin>>n>>m;
  29. for(int i=1;i<=n;i++){
  30. for(int j=1;j<=n;j++){
  31. char c;
  32. cin>>c;
  33. if (c=='1') t[i][j]=true;
  34. else t[i][j]=false;
  35. }
  36. }
  37. for(int i=0;i<m;i++){
  38. cnt=1;//包括起点在内
  39. int x1,y1;
  40. scanf("%d%d",&y1,&x1);
  41. if (a[y1][x1]>0) printf("%d\n",ma[(a[y1][x1])]);
  42. else{
  43. step[y1][x1]=false;//注意起点的标记
  44. a[y1][x1]=i+1;
  45. dfs(x1,y1,i+1);
  46. ma[i+1]=cnt;
  47. /*
  48. 这是之前的一个做法,直接在序号标记数组里记录连通块数量,但还是超时,所以改成了标号,根据标号查找联通量
  49. for(int in=1;in<=n;in++){
  50. for(int jn=1;jn<=n;jn++){
  51. if (!step[in][jn]) a[in][jn]=cnt;
  52. }
  53. }
  54. */
  55. printf("%d\n",cnt);
  56. }
  57. }
  58. return 0;
  59. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注