【算法分享】方向迷宫 + 魔法路径判定:BFS 与 0-1 BFS 双解法详解

📖 1. 题目简述

  • 你在一个 n × m 的矩阵中移动

  • 每个格子有一个方向: U D L R

  • 你不能随意移动,只能按照格子的方向移动

  • 你有 k 次魔法机会,可以修改任意一个格子的方向

  • 问:最多用 k 次魔法,是否能从 (1,1) 达到 (n,m)?

很快想到图论模型:每个格子就是图中的节点,不同方向有不同代价!这其实是一个典型的 0-1 BFS 最短路径问题

附上题目链接(牛客网):https://ac.nowcoder.com/acm/contest/115184/D

🎯 2. 解题思路概览。

本题实质是一个图上的最短路径问题,魔法次数就是代价:很快想到图论模型:每个格子就是图中的节点,不同方向有不同代价!这其实是一个典型的 0-1 BFS 最短路径问题

  1. 根据方向移动,一步一步进行

  2. 如果方向正确,移动成功,耗费 0

  3. 如果方向错误,需要改方向,耗费 1 (使用魔法)

点和边 说明
每个格子 (x, y) 是一个点
(x, y) 进行一步移动 是一条边
边权 如果方向正确,为 0;否则为 1

🧠 3. 核心思想

  1. 使用 deque 保持两端

  2. 当耗费 = 0 时,push_front ( 优先执行 )

  3. 当耗费 = 1 时,push_back

假设我们有如下矩阵:

起点
↓
[ R, D ]
[ U, L ]
      ↑
    终点

对应索引:

(0,0) → R → (0,1)
             ↓D
         (1,1)

原始路径

  • (0,0) → R → (0,1)

  • (0,1) → D → (1,1)

如果方向正确,一路代价为 0。

修改方向的情形

  • 若 (0,0) 是 U,则必须魔法改为 R,代价 1

以此类推。

🛠️ 4. 解法实现:0-1 BFS

deque<pair<int, int>> dq;
dist[0][0] = 0;
dq.emplace_front(0, 0);

// 遍历所有方向
for (int d = 0; d < 4; ++d) 
{
    int nx = x + dx[d], ny = y + dy[d];
    if (grid[x][y] == dir[d]) 
      cost = 0; 
    else 
      cost = 1;
}

✍️ 5. Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int dx[4] = {-1, 1, 0, 0}; // U D L R
const int dy[4] = {0, 0, -1, 1};
const char dir[4] = {'U', 'D', 'L', 'R'};

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t;
    cin>>t;
    while(t--) {
        int n,m,k;
        cin>>n>>m>>k;
        vector<string> v(n);
        for(int i=0;i<n;i++)
            cin>>v[i];

        vector<vector<int> >dist(n,vector<int>(m,INT_MAX));
        deque<pair<int,int> >q;

        dist[0][0]=0;
        //从坐标(0,0)开始搜索
        q.emplace_front(0,0);

        while(!q.empty()) {
            pair<int,int>p = q.front();
            int x = p.first;
            int y = p.second;
            q.pop_front();

            for(int i=0;i<4;i++) {
                int nx=x+dx[i];
                int ny=y+dy[i];
                if(nx>=0 && nx<n && ny>=0 && ny<m) {
                    // 计算从当前格子 (x, y) 走向第 i 个方向的实际代价
                    int cost=(v[x][y]==dir[i])?0:1;
                    if(dist[nx][ny]>dist[x][y]+cost) {
                        dist[nx][ny]=dist[x][y]+cost;
                        //双端队列核心
                        if (cost==0)
                            //放在前面,更优路径,优先处理
                            q.emplace_front(nx,ny);
                        else
                            //放在后面,次优路径,稍后处理
                            q.emplace_back(nx,ny);
                    }
                }
            }
        }
        if (dist[n-1][m-1]<=k)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

✅ 时间复杂度分析

  • 每个点最多访问 1 次(权值0 or 1)

  • 总点数 ≤ 1e6,所以 0-1 BFS 的复杂度为 O(n × m),完全可以通过

posted @ 2025-08-06 21:21  开珥  阅读(37)  评论(0)    收藏  举报