迷宫:
UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR
思路:
察某个点上的人,他沿着指示牌一直走,或者最后能走出去,或者没走出去又兜回来了。
这就是“一路到底”,是典型的 DFS (深度优先算法)
题解1:
直接采用DFS算法,开始搜索
#include<bits/stdc++.h>
using namespace std;
const int n = 10;
char mp[n + 2 ][n + 2]; //二维矩阵存储迷宫
bool vis[n + 2][n + 2]; //记忆化功能:判断路是否曾经走过,走过那就标个true
//如果第二次遇到,说明你进入了死循环,具体见dfs函数
int ans = 0;
int cnt = 0;
bool dfs(int i, int j){
//递归出口
if(i < 0 || i > n - 1 || j < 0 || j > n - 1) return true;
if(vis[i][j]) return false;
cnt++; //统计dfs使用了多少次
vis[i][j] = true; //标记这块地已经走过
//递归条件
if(mp[i][j] == 'L') return dfs(i, j - 1);
if(mp[i][j] == 'R') return dfs(i, j + 1);
if(mp[i][j] == 'U') return dfs(i + 1, j);
if(mp[i][j] == 'D') return dfs(i - 1, j);
}
int main(){
//输入每一个格子中的字符:
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
cin >> mp[i][j];
}
}
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
memset(vis, 0, sizeof(vis));
if(dfs(i, j)) ans++;
}
}
cout << "ans=" << ans <<", cnt=" << cnt << endl;
return 0;
}
时间复杂度为O(n^4)
考虑最坏情况,迷宫如下:
RRRRRRRRRD
DLLLLLLLLL
RRRRRRRRRD
DLLLLLLLLL
RRRRRRRRRD
DLLLLLLLLL
RRRRRRRRRD
DLLLLLLLLL
RRRRRRRRRD
DLLLLLLLLL
意味你最多需要从头走到尾,然后原本你需要遍历两个for,然后里层for最多又要执行n^2次,所以时间复杂度为 O(n^4)
题解2:
接下来,讲讲采用 记忆化 的技巧
你可以认为,此方法是 设置一个路标,提前告诉你接下来路能否走通
在题解1的基础上,补充一个二维数组solve,数组中填满了路标:
如果路标上记录为1,那接下来就有路
如果路标上记录为2,那接下来就无路
#include<bits/stdc++.h>
using namespace std;
char mp[12][12]; //存放字符
bool vis[12][12]; //判断路是否曾经走过
int solve[12][12]; //记忆化路标,见dfs()中的使用
int ans = 0;
int cnt = 0;
bool dfs(int i, int j){
//递归出口:
if(i < 0 || j < 0 || i > 9 || j > 9) return true;
if(vis[i][j]) return false;
//优化代码: 记忆化路标
//记忆化:路径标记,确定点(i,j)接下来能否走出去
if(solve[i][j] == 1) return true;
if(solve[i][j] == 2) return false;
cnt++;
//记忆化:标记已搜索
vis[i][j] = true;
//递归条件: //注意 二维矩阵 的坐标系
if(mp[i][j] == 'L'){
if(dfs(i, j - 1)){
solve[i][j] = 1;
return true;
}else{
solve[i][j] = 2;
return false;
}
}
if(mp[i][j] == 'R'){
if(dfs(i, j + 1)){
solve[i][j] = 1;
return true;
}else{
solve[i][j] = 2;
return false;
}
}
if(mp[i][j] == 'U'){
if(dfs(i - 1, j)){
solve[i][j] = 1;
return true;
}else{
solve[i][j] = 2;
return false;
}
}
if(mp[i][j] == 'D'){
if(dfs(i + 1, j)){
solve[i][j] = 1;
return true;
}else{
solve[i][j] = 2;
return false;
}
}
}
int main(){
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
cin >> mp[i][j];
}
}
memset(solve, 0, sizeof(solve));
for(int i = 0; i < 10; i++){
for(int j = 0; j < 10; j++){
memset(vis, 0, sizeof(vis));
if(dfs(i, j)) ans++;
}
}
cout << ans << endl;
cout << cnt << endl;
return 0;
}
时间复杂度:O(n^2)
补充函数:memset
简单说,本题主要用它来让二维数组中的数全部清零
void *memset(void *str, int c, size_t n)
- str -- 指向要填充的内存块。
- c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
- n -- 要被设置为该值的字符数。
参考:蓝桥杯2022一站式通关班