欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

洛谷 P1141 01迷宫题解

程序员文章站 2022-06-02 13:35:01
题目链接:https://www.luogu.org/problem/P1141 题目描述 有一个仅由数字00与11组成的n \times nn×n格迷宫。若你位于一格0上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格1上,那么你可以移动到相邻44格中的某一格00上。 你的任务是:对 ......

题目链接:https://www.luogu.org/problem/p1141

题目描述

有一个仅由数字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≤10n10;

对于40\%40%的数据,n≤50n50;

对于50\%50%的数据,m≤5m5;

对于60\%60%的数据,n≤100,m≤100n100,m100;

对于100\%100%的数据,n≤1000,m≤100000n1000,m100000。


题解

先介绍采用裸的bfs,当然不能满分。再介绍如何优化得到满分。

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 #include <string.h>
 6 
 7 using namespace std;
 8 
 9 struct node
10 {
11     int x, y;
12 };
13 node q[1000005]; 
14 
15 const int maxn = 1005;
16 int n, m, a, b, c, d, front, last, step; 
17 int pos[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
18 char abc[maxn][maxn]; // 存储输入的矩阵信息 
19 bool vis[maxn][maxn]; // 是否已经遍历过该点 
20 
21 
22 void bfs()
23 {
24     node now;
25     now.x = a;
26     now.y = b;
27     vis[a][b] = 1;
28     
29     front = last = 0;
30     q[last] = now;
31     last++;
32     while(front < last)
33     {
34         now = q[front++];
35         for(int i = 0; i < 4; i++)
36         {
37             int nx = now.x + pos[i][0]; 
38             int ny = now.y + pos[i][1]; 
39             if(nx <= n && nx > 0 && ny <= n && ny > 0 
40                 && vis[nx][ny] == false 
41                 && abc[now.x][now.y] != abc[nx][ny]) 
42             {
43                 vis[nx][ny] = true;
44                 q[last].x = nx;
45                 q[last].y = ny;
46                 step++;
47                 last++;
48             }
49         } 
50     }
51 }
52 
53 int main()
54 {
55     cin >> n >> m;
56     for(int i = 1; i <= n; i++)
57     {
58         for(int j = 1; j <= n; j++)
59         {
60             cin >> abc[i][j];
61         }
62     }
63     for(int i = 1; i <= m; i++)
64     {
65         cin >> a >> b;
66         step = 1;
67         bfs();
68         cout << step << endl;
69         memset(vis, 0, sizeof(vis));
70     }
71     return 0;
72 }

裸的bfs并没有什么技巧,只是注意q队列不要太小,太小会导致wa。这个代码会有3个测试点tle。

 之所以会出现tle,主要是有很多次询问,每次询问都做了一次bfs,要优化代码就要减少bfs的次数。注意到这样一个事实:如果迷宫中存在连通块,则连通块中各格子到其他格子的个数是相同的。而求连通块本身就是利用bfs实现的。下面就是利用连通块进行优化的代码。

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 #include <string.h>
 6 
 7 using namespace std;
 8 
 9 struct node
10 {
11     int x, y;
12 };
13 node q[1000005];
14 int cnt[1000005];
15 
16 const int maxn = 1005;
17 int n, m, a, b, c, d, front, last, step, num; 
18 int pos[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
19 char abc[maxn][maxn]; // 存储输入的矩阵信息 
20 bool vis[maxn][maxn]; // 是否已经遍历过该点
21 int map[maxn][maxn]; // 用于对连通块染色 
22 
23 
24 void bfs()
25 {
26     node now, next;
27     now.x = a;
28     now.y = b;
29     map[a][b] = num;
30     vis[a][b] = 1;
31     step = 1;
32     
33     front = last = 0;
34     q[last] = now;
35     last++;
36     while(front < last)
37     {
38         now = q[front++];
39         for(int i = 0; i < 4; i++)
40         {
41             int nx = now.x + pos[i][0]; 
42             int ny = now.y + pos[i][1]; 
43             if(nx <= n && nx > 0 && ny <= n && ny > 0 
44                 && vis[nx][ny] == false 
45                 && abc[now.x][now.y] != abc[nx][ny]) 
46             {
47                 vis[nx][ny] = true;
48                 q[last].x = nx;
49                 q[last].y = ny;
50                 map[nx][ny] = num;
51                 step++;
52                 last++;
53             }
54         } 
55     }
56     cnt[num] = step;
57     num++;
58 }
59 
60 int main()
61 {
62     cin >> n >> m;
63     for(int i = 1; i <= n; i++)
64     {
65         for(int j = 1; j <= n; j++)
66         {
67             cin >> abc[i][j];
68         }
69     }
70     num = 1;
71     for(int i = 1; i <= m; i++)
72     {
73         cin >> a >> b;
74         if(map[a][b] == 0) 
75         {
76             bfs();            
77         }    
78         cout << cnt[map[a][b]] << endl;
79     }
80     return 0;
81 }

其中的map数组是用来存储连通块的染色信息的。如果格子对应的map数据为0,说明没有做过bfs。cnt数组存储着每个连通块所对应的格子个数。经过这次优化,就可以ac了。