0
点赞
收藏
分享

微信扫一扫

[洛谷] P1141 01迷宫


P1141 01迷宫

  • ​​1.题目​​
  • ​​2.分析​​
  • ​​3.代码​​
  • ​​1.dfs 70 TLE​​
  • ​​2.dfs + 记忆搜索过的点[连通块] 90 TLE​​
  • ​​试了一下,吸氧优化后还是通过不了,第二个测试点太毒瘤了​​
  • ​​3.dfs + 连通块染色思想 (对2.的优化) AC​​
  • ​​4.bfs + 染色 AC​​
  • ​​4.总结​​
  • ​​5.更新日志​​

1.题目

题目描述

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

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

输入格式

行为两个正整数

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

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

输出格式

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

样例输入 #1

2 2
01
10
1 1
2 2

样例输出 #1

4
4

提示

所有格子互相可达。

对于的数据,

对于的数据,

对于的数据,

对于的数据,

对于的数据,

2.分析

记忆化搜索~

3.代码

1.dfs 70 TLE

#include <iostream>
using namespace std;
const int N = 1e3 + 10;
#include <cstring> //memset !
char g[N][N];
bool st[N][N];
int n, q;
int cnt;
//最长路径
void dfs(int x, int y)
{
//visited
if (st[x][y])
return;
//否则
++cnt;
st[x][y] = true;
int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
for (int i = 0; i < 4; ++i)
{
int a = x + dx[i], b = y + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= n && (g[x][y] == '0' && g[a][b] == '1' || g[x][y] == '1' && g[a][b] == '0'))
dfs(a, b);
}
}

int main()
{

scanf("%d%d", &n, &q);
getchar(); //吞\n
for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
while (q--)
{
//init
memset(st, 0, sizeof st);
cnt = 0;
int x, y;
scanf("%d%d", &x, &y);
dfs(x, y);
printf("%d\n", cnt);
}
return 0;
}

[洛谷] P1141 01迷宫_深度优先_32

2.dfs + 记忆搜索过的点[连通块] 90 TLE

由于在搜索某条路径时,包含了很多点,则将这些点均赋值为最终路径长度,避免重复搜索

#include <iostream>
using namespace std;
const int N = 1e3 + 10;
#include <cstring> //memset !
#include <set> //记录路径
typedef pair<int, int> PII;
set<PII>SP;

char g[N][N];
bool st[N][N];
int d[N][N];
int n, q;
int cnt;
//最长路径
void dfs(int x, int y)
{
//visited
if (st[x][y])
return;
//否则
++cnt;
st[x][y] = true;
SP.insert({x,y}); //记录路径
int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
for (int i = 0; i < 4; ++i)
{
int a = x + dx[i], b = y + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= n && (g[x][y] == '0' && g[a][b] == '1' || g[x][y] == '1' && g[a][b] == '0'))
dfs(a, b);
}
}

int main()
{
scanf("%d%d", &n, &q);
getchar(); //吞\n
for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);

while (q--)
{
int x, y;
scanf("%d%d", &x, &y);
if (d[x][y]) {
printf("%d\n", d[x][y]);
}
else
{
//init
memset(st, 0, sizeof st);
SP.clear(); //清空路径记录
cnt = 0;
dfs(x, y);

for (auto x : SP)
{
int a = x.first, b = x.second;
d[a][b] = cnt;
}

printf("%d\n", cnt);
}
}
return 0;
}

[洛谷] P1141 01迷宫_算法_33

试了一下,吸氧优化后还是通过不了,第二个测试点太毒瘤了

[洛谷] P1141 01迷宫_图论_34

3.dfs + 连通块染色思想 (对2.的优化) AC

可以将不同的连通块染成不同的颜色,即做不同的标记,给每个标记赋上不同的值即可

//dfs+染色
#include <iostream>
using namespace std;
#include <cstring>
const int N = 1e3 + 10;
const int M = 1e5 + 10;

int cr[M]; //记录每个颜色所对应的答案
char g[N][N]; //迷宫
int d[N][N]; //标记连通块 并 染色
int n, m;

void dfs(int x, int y, int fg, int col)
{
//base case 已经写到 for循环中

d[x][y] = col; //标记为 col
cr[col]++; //标记为col的路径长度+1
int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
for (int i = 0; i < 4; ++i)
{
int a = x + dx[i], b = y + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= n && d[a][b] == -1 && g[a][b]-'0'==!fg)
dfs(a, b, !fg, col);
}
}

int main()
{
scanf("%d%d", &n, &m);

for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);

memset(d, -1, sizeof d);

for (int i = 0; i < m; ++i)
{
int x, y;
scanf("%d%d", &x, &y);

if (d[x][y] == -1)//未遍历
dfs(x, y, g[x][y] - '0', i);
printf("%d\n", cr[d[x][y]]);
}

return 0;
}

4.bfs + 染色 AC

#include <iostream>
using namespace std;
#include <queue>
#include <cstring> //memset

const int N = 1e3 + 10, M = 1e5 + 10;
typedef pair<int, int> PII;
queue<PII> q;
char g[N][N]; //迷宫
int d[N][N]; //搜索
int col[M];
int n, m;
int k; //连通图标记

void bfs(int x, int y)
{
//init
d[x][y] = k;
col[k]++;
q.push({ x,y });

int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
while (q.size())
{
//取队头
auto t = q.front();
q.pop();
for (int i = 0; i < 4; ++i)
{
int a = t.first + dx[i], b = t.second + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= n && d[a][b] == -1 && (g[t.first][t.second] ^ 48) + (g[a][b] ^ 48) == 1)
{
d[a][b] = k;
col[k]++;
q.push({ a,b });
}
}
}
}

int main()
{
scanf("%d%d", &n, &m);

for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);

//init dist
memset(d, -1, sizeof d);

for (int i = 0; i < m; ++i)
{
int x, y;
scanf("%d%d", &x, &y);

if (d[x][y] == -1)
{
//new 连通块
k++;
bfs(x, y);
}
printf("%d\n", col[d[x][y]]);
}
return 0;
}

[洛谷] P1141 01迷宫_图论_35


dfs的优势在于所占内存较少,速度上比bfs慢些~

4.总结

bfs 、 dfs 、染色~

5.更新日志

2022.8.27 整理

欢迎交流、讨论、指正~
不正确、不理解之处欢迎评论留言~


举报

相关推荐

0 条评论