答案是肯定的。
在网格(Grid)地图里找迷宫路径,绝对是深搜(DFS)和广搜(BFS)的最经典应用场景。
在 2 小时的上机考试中,你应该如何选择?我给你一个最功利的判断标准:
- 如果题目只要求“找到一条路径”(或者说“能不能到达终点”):无脑用 DFS。
- 原因:代码短,逻辑简单(递归),不需要维护队列,写起来最快。
- 如果题目明确要求“找到最短路径”:必须用 BFS。
- 原因:DFS 找出来的路通常是绕弯的,只有 BFS 层层外扩的特性才能保证找到的是最短的。
鉴于考试时间紧,且往年题目(如 2023 小雪人)通常只要求“找到任意一条符合条件的路径”,我强烈建议你熟练掌握 DFS 的写法。
一、 迷宫 DFS 算法模板(背下来)
这是一个通用的网格 DFS 模板。
假设 map[x][y] == 0 是路,1 是墙。
数据结构准备:
在 MainWindow 类中:
std::vector<QPoint> path; // 记录路径,用于最后画图
bool visited[20][20]; // 访问标记,防止死循环 (假设最大20x20)
// 或者用 vector<vector<bool>> visited;核心代码:
// 返回值 bool: true表示找到路了,false表示没找到
bool MainWindow::dfs(int x, int y) {
// 1. 【越界检查】 & 【障碍检查】 & 【已访问检查】
if (x < 0 || x >= M || y < 0 || y >= N) return false; // 越界
if (map[x][y] == 1) return false; // 撞墙
if (visited[x][y]) return false; // 走回头路
// 2. 【记录当前点】
path.push_back(QPoint(x, y)); // 加入路径
visited[x][y] = true; // 标记已走过
// 3. 【终点判断】
if (x == endX && y == endY) {
return true; // 到达终点,大功告成,一路返回 true
}
// 4. 【递归试探】 (上下左右)
// 方向数组: 下, 右, 上, 左
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
for (int i = 0; i < 4; ++i) {
int nextX = x + dx[i];
int nextY = y + dy[i];
// 关键点:如果深层递归返回 true,说明找到路了,我也返回 true
if (dfs(nextX, nextY)) {
return true;
}
}
// 5. 【回溯 (Backtracking)】
// 如果四个方向都走不通,说明 (x,y) 是死胡同
path.pop_back(); // 把它从路径里踢出去
// 注意:如果是找"一条"路径,通常不需要 visited[x][y] = false;
// 这样能保留"死胡同"标记,防止以后再进来,效率更高。
return false;
}二、 如何把路径“画”出来?
题目提到的“把路径画出来”通常有两种画法,你要看题目截图:
画法 1:格子填色(最常见)
就是我们之前练习的,把路径上的格子涂成蓝色/黄色。
实现思路:
- 执行
dfs(startX, startY)成功后,path向量里存的就是正确的坐标序列。 - 在
paintEvent里,先画地图背景。 - 再遍历
path数组,把对应的格子重画一遍颜色。
void MainWindow::paintEvent(QPaintEvent *) {
QPainter painter(this);
// ... 画网格背景 ...
// 画路径
painter.setBrush(Qt::blue); // 设置路径颜色
for (const auto& p : path) {
// 转换坐标: 行=p.x(), 列=p.y() (假设你DFS里x是行)
// 记得你的像素转换公式: margin + index * size
double px = leftMargin + p.y() * cellW;
double py = topMargin + p.x() * cellH;
painter.drawRect(QRectF(px, py, cellW, cellH));
}
}画法 2:画线条连接(Polyline)
如果题目要求像手机锁屏图案那样,用线条把中心点连起来。
实现思路:
- DFS 跑完拿到
path。 - 在
paintEvent里使用painter.drawLine。
void MainWindow::paintEvent(QPaintEvent *) {
// ...
painter.setPen(QPen(Qt::red, 3)); // 红色线条,线宽3
for (size_t i = 0; i < path.size() - 1; ++i) {
QPoint p1 = path[i];
QPoint p2 = path[i+1];
// 算出两个格子的【中心点】像素坐标
// CenterX = Margin + Col * W + W/2
double x1 = leftMargin + p1.y() * cellW + cellW/2;
double y1 = topMargin + p1.x() * cellH + cellH/2;
double x2 = leftMargin + p2.y() * cellW + cellW/2;
double y2 = topMargin + p2.x() * cellH + cellH/2;
painter.drawLine(QPointF(x1, y1), QPointF(x2, y2));
}
}总结
- 找迷宫路径 = DFS(除非特别要求最短路径)。
- 它的核心是:标记 visited → 递归邻居 → 回溯 pop。
- 把这个模板背熟,考试时只需要改一下
if (map[x][y] == 1)这种判断墙的条件即可。