最短路径C++

问题描述

小蓝有一天误入了一个混境之地。

好消息是: 他误打误撞拿到了一张地图,并从中获取到以下信息:

  1. 混境之地是一个 n·m大小的矩阵,其中#表示墙,无法通行,.表示普通的道路,k表示散落在地图中的钥匙。
  2. 他现在所在位置的坐标为(A,B),而这个混境之地出口的坐标为(C,D),当站在出口时且携带最少一把钥匙即表示可以逃离混境之地。
  3. 地图中可能存在不止一把钥匙。

坏消息是:

  1. 地图中可能没有钥匙。

小蓝可以往上下左右四个方向行走,每走一步耗时一分钟。

小蓝想知道他能否逃离这个混境之地,如果可以逃离这里,输出最少需要消耗多少时间,反之输出-1。

输入格式

第一行输入两个正整数 n, m, 表示矩阵的大小。

第二行输入四个正整数 A, B, C, D, 表示小蓝当前所在位置的坐标,以及混境之地出口的坐标。

接下来输入 n行, 每行 m个字符, 表示混境之地的地图, 其中#表示墙, 无法通行, .表示普通的道路, k表示散落在地图中的钥匙。

输出格式

输出数据共一行一个字符串:

  • 若小蓝可以逃离混境之地, 则输出最少需要消耗多少时间。
  • 若小蓝无法逃离混境之地, 则输出 -1。

样例输入1

复制代码
5 5
1 1 5 5
....#
#..#..
k.#..
.#...
...#.

样例输出1

复制代码
12

样例解释1

从(1,1)到(5,5)的最短道路为:

  1. (1,1) → (1,2) → (2,2) → (3,2) → (3,1) 拿到钥匙。
  2. (3,1) → (4,1) → (5,1) → (5,2) → (5,3) → (4,3) → (4,4) → (4,5) → (5,5) 到达终点。

问题思路

本质上这是一个考 最短路径 的问题,用 BFS 解决

有两种情况

1. 图上只有一个钥匙

因为图上只有一个钥匙,且出去的条件中需要一把钥匙。即我们必须经过钥匙的位置。

假设我到钥匙的路径距离为w,钥匙到出口路径的距离为d。

因为走一步算一分钟,则总时长=w+d

关键:

计算 我到钥匙的最短路径 + 钥匙到出口的最短路径

有两个方案:

(1)把钥匙作为出发点,求钥匙-》我的最短路径 + 钥匙-》出口的最短路径。相加得到总体的最短路径

(2)把钥匙作为终点,求 我-》钥匙的最短路径 + 终点-》钥匙的最短路径相加得到总体的最短路径

2. 图上有多个钥匙

因为图上有多个钥匙,为了求最短路径,我们需要找出哪个钥匙到起点和终点的最短路径更短。

  • 如果按照方案一去求,钥匙可能在的点数为(n×m),点的数量为(n×m)那么时间复杂度最坏的情况下为 O(n2⋅m2),时间复杂度较高。
  • 如果按照方案二区求,则对起点和终点进行 BFS,由于点的数量为 n·m ,故时间复杂度为 O(n·m),在枚举所有的钥匙的情况下,钥匙的数量最多为 n·m枚举的复杂度为 O(n·m),计算的时间复杂度为O(1),故总体复杂度为O(n·m+n·m),即O(n·m),时间复杂度较低,选择方案二

思路

代码

cpp 复制代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1e3 + 10;

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int n, m;
int A, B, C, D;
char g[N][N];
vector<vector<int>> dist1, dist2;

void bfs(int x, int y, vector<vector<int>> &dist)
{
    dist[x][y] = 0;
    queue<PII> q;
    q.push({x, y});
    
    while (q.size())
    {
        auto t = q.front();
        q.pop();
        
        for (int i = 0; i < 4; ++ i )
        {
            int tx = t.x + dx[i], ty = t.y + dy[i];
            if (tx < 0 || ty < 0 || tx >= n || ty >= m || g[tx][ty] == '#')
                continue;
            if (dist[tx][ty] <= dist[t.x][t.y] + 1)
                continue;
            dist[tx][ty] = dist[t.x][t.y] + 1;
            q.push({tx, ty});
        }
    }
}

int main()
{
    cin >> n >> m;
    cin >> A >> B >> C >> D;
    A --, B --, C --, D --;
    
    for (int i = 0; i < n; ++ i )
        cin >> g[i];
    
    dist1 = vector<vector<int>>(n, vector<int>(m, 0x3f3f3f3f));
    dist2 = vector<vector<int>>(n, vector<int>(m, 0x3f3f3f3f));
    
    bfs(A, B, dist1);
    bfs(C, D, dist2);
    
    int res = 0x3f3f3f3f;
    for (int i = 0; i < n; ++ i )
        for (int j = 0; j < m; ++ j )
            if (g[i][j] == 'k')
                res = min(res, dist1[i][j] + dist2[i][j]);
    
    if (res == 0x3f3f3f3f)
        puts("-1");
    else
        cout << res << endl;
    
    return 0;
}
相关推荐
青山木3 小时前
Hot 100 --- 二叉树与递归
java·数据结构·算法·leetcode·深度优先
jason成都4 小时前
GNSS-QC 数据清洗功能全面增强|滑坡监测实测验证,适配 rtklib_java 高精度解算链路
java·gnss
前端工作日常4 小时前
我学习到的Java概念
java·后端
卓怡学长4 小时前
w263基于springboot + vue 健康饮食管理系统
java·数据库·vue.js·spring boot·spring·intellij-idea
r_oo_ki_e_4 小时前
Java反射机制学习笔记
java·笔记·学习
珠海西格电力4 小时前
数据采集与治理:零碳园区管理系统的 “生命线”
大数据·人工智能·算法·架构·能源
九皇叔叔4 小时前
RHEL9.8 配置本地镜像仓库
android·java·缓存
范什么特西4 小时前
苍穹外卖体会
java
Nontee4 小时前
数据类型与包装类 — 一个新手学Java的数据类型笔记
java·笔记·python
●VON4 小时前
HarmonyKit | 鸿蒙新特性:router 导航 API 从 pushUrl 到 UIContext 的演进
算法·华为·交互·harmonyos