惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
WordPress大学
WordPress大学
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
A
About on SuperTechFans
Stack Overflow Blog
Stack Overflow Blog
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
腾讯CDC
爱范儿
爱范儿
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
V
Visual Studio Blog
有赞技术团队
有赞技术团队
U
Unit 42
D
Docker
小众软件
小众软件
F
Full Disclosure
I
Intezer
Scott Helme
Scott Helme
P
Privacy International News Feed
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
Google DeepMind News
Google DeepMind News
B
Blog
Martin Fowler
Martin Fowler
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Vercel News
Vercel News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Spread Privacy
Spread Privacy
宝玉的分享
宝玉的分享
S
Security Affairs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
月光博客
月光博客
C
Cisco Blogs
云风的 BLOG
云风的 BLOG
Schneier on Security
Schneier on Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Threat Research - Cisco Blogs
量子位
Hacker News - Newest:
Hacker News - Newest: "LLM"
H
Heimdal Security Blog
N
Netflix TechBlog - Medium
H
Hacker News: Front Page
P
Proofpoint News Feed
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
S
Schneier on Security

博客园 - zealsoft

洛谷 P1816 忠诚题解 洛谷 P2384 最短路题解 洛谷 P2725 邮票题解 洛谷 P2722 总分题解 洛谷 P1219 八皇后题解 洛谷 P2921 在农场万圣节Trick or Treat on the Farm题解 洛谷 P1162 填涂颜色题解 洛谷 P1330 封锁阳光大学题解 洛谷 P1032 字串变换题解 洛谷 P1443 马的遍历题解 洛谷 P1280 尼克的任务题解 洛谷 P1020导弹拦截题解 VisualSVNServer无法卸载也无法安装,报告不是有效的MOF文件(0x8004401e)错误 视频捕捉的格式问题 一个VxWorks源代码网站 找个轻量级的Log库还挺难 TAU G2中的BitString和OctetString W32.Downadup.autorun病毒的清除 如何用Visual Studio 2005编译Wireshark的插件
洛谷 P1141 01迷宫题解
zealsoft · 2019-08-09 · via 博客园 - zealsoft

题目链接: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行,对于每个询问输出相应答案。

输入输出样例

说明/提示

所有格子互相可达。

对于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了。