每周题解:拯救大兵瑞恩

题目描述

1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。

瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图。

迷宫的外形是一个长方形,其南北方向被划分为 N N N 行,东西方向被划分为 M M M 列, 于是整个迷宫被划分为 N × M N×M N×M 个单元。

每一个单元的位置可用一个有序数对 (单元的行号, 单元的列号) 来表示。

南北或东西方向相邻的 2 2 2 个单元之间可能互通,也可能有一扇锁着的门,或者是一堵不可逾越的墙。

注意: 门可以从两个方向穿过,即可以看成一条无向边。

迷宫中有一些单元存放着钥匙,同一个单元可能存放 多把钥匙,并且所有的门被分成 P P P 类,打开同一类的门的钥匙相同,不同类门的钥匙不同。

大兵瑞恩被关押在迷宫的东南角,即 ( N , M ) (N,M) (N,M) 单元里,并已经昏迷。

迷宫只有一个入口,在西北角。也就是说,麦克可以直接进入 ( 1 , 1 ) (1,1) (1,1) 单元。

另外,麦克从一个单元移动到另一个相邻单元的时间为 1 1 1,拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。

试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。

输入格式

第一行有三个整数,分别表示 N , M , P N,M,P N,M,P 的值。

第二行是一个整数 k k k,表示迷宫中门和墙的总数。

接下来 k k k 行,每行包含五个整数, X i 1 , Y i 1 , X i 2 , Y i 2 , G i X_{i1},Y_{i1},X_{i2},Y_{i2},G_i Xi1,Yi1,Xi2,Yi2,Gi:当 G i ≥ 1 G_i≥1 Gi1 时,表示 ( X i 1 , Y i 1 ) (X_{i1},Y_{i1}) (Xi1,Yi1) 单元与 ( X i 2 , Y i 2 ) (X_{i2},Y_{i2}) (Xi2,Yi2) 单元之间有一扇第 G i G_i Gi 类的门,当 G i = 0 G_i=0 Gi=0 时,表示 ( X i 1 , Y i 1 ) (X_{i1},Y_{i1}) (Xi1,Yi1) 单元与 ( X i 2 , Y i 2 ) (X_{i2},Y_{i2}) (Xi2,Yi2) 单元之间有一面不可逾越的墙。

接下来一行,包含一个整数 S S S,表示迷宫中存放的钥匙的总数。

接下来 S S S 行,每行包含三个整数 X i 1 , Y i 1 , Q i X_{i1},Y_{i1},Q_i Xi1,Yi1,Qi,表示 X i 1 , Y i 1 X_{i1},Y_{i1} Xi1,Yi1 单元里存在一个能开启第 Q i Q_i Qi 类门的钥匙。

输出格式

输出麦克营救到大兵瑞恩的最短时间。

如果问题无解,则输出 -1

样例 #1

样例输入 #1

4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0 
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
2
2 1 2 
4 2 1

样例输出 #1

14

提示

【样例解释】
测试样例的迷宫如下图所示
在这里插入图片描述
【数据范围】

∣ X i 1 − X i 2 ∣ + ∣ Y i 1 − Y i 2 ∣ = 1 |X_{i1}−X_{i2}|+|Y_{i1}−Y_{i2}|=1 Xi1Xi2+Yi1Yi2=1,
0 ≤ G i ≤ P 0≤G_i≤P 0GiP,
1 ≤ Q i ≤ P 1≤Q_i≤P 1QiP,
1 ≤ N , M , P ≤ 10 1≤N,M,P≤10 1N,M,P10,
1 ≤ k ≤ 150 1≤k≤150 1k150

算法思想

状态表示

根据题目描述,从 ( 1 , 1 ) (1,1) (1,1)出发,每次移动一个单元,时间为 1 1 1,求的是走到 ( n , m ) (n,m) (n,m)点的最短时间。如果不考虑钥匙和门的情况下,可以直接用BFS求解从 ( 1 , 1 ) (1, 1) (1,1)走到任意一点 ( x , y ) (x,y) (x,y)的最小步数 d i s ( x , y ) dis(x,y) dis(x,y)

加上钥匙和门之后, d i s ( x , y ) dis(x,y) dis(x,y)显然无法表达走到点 ( x , y ) (x,y) (x,y)时拥有钥匙的状态。那么可以进行拆点,利用状态压缩的思想,引入一个 s t a t e state state d i s ( x , y , s t a t e ) dis(x,y,state) dis(x,y,state)表示从 ( 1 , 1 ) (1, 1) (1,1)走到任意 ( x , y ) (x,y) (x,y)、并且当前拥有的钥匙状态为 s t a t e state state时的最小步数。例如 s t a t e state state二进制为 ( 0110 ) 2 (0110)_2 (0110)2时,表示持有第 1 , 2 1,2 1,2类钥匙,因为钥匙编号从 1 1 1开始,要判断是否持有第 i i i类钥匙时,只需要判断state >> i & 1是否为 1 1 1即可。

为了方便判断两个格子的状态(互通、墙、还是门),这里可以将二维坐标 ( x , y ) (x,y) (x,y)转换成一维的编号 z z z,如下图所示:
在这里插入图片描述
这样 d i s ( z , s t a t e ) dis(z,state) dis(z,state)表示走到编号为 z z z的格子、并且当前拥有的钥匙状态为 s t a t e state state时的最小步数,其中 z = ( x − 1 ) × m + y z=(x-1)\times m + y z=(x1)×m+y

状态计算

在计算 d i s ( z , s t a t e ) dis(z,state) dis(z,state)时,由于只能向东南西北 4 4 4个方向进行移动,那么可以利用偏移数组进行状态转移,在转移过程中可以分为下面几种情况:

  • 两个相邻格子间有墙,不能转移;
  • 两个相邻格子间有门,没有该类门钥匙,不能转移;
  • 两个相邻格子间有门,拥有该类门钥匙,能够转移,最小步数 + 1 +1 +1
  • 两个相邻格子间没有障碍,能够转移,最小步数 + 1 +1 +1

在转移过程中还要考虑拥有的钥匙状态:

  • 如果转移到的格子上没有钥匙,则钥匙状态不变
  • 如果转移到的格子上拥有钥匙的状态为 s s s,则钥匙状态更新为s=s|state

当走到终点时,也就是编号为 n × m n\times m n×m的格子,此时不关心到达终点时拥有钥匙的状态,只要到达了终点就能成功营救大兵瑞恩。

可以看出在整个状态计算的过程中,只要状态转移了,步长都是+ 1 1 1的,使用普通的BFS就可以解决了。

时间复杂度

BFS算法每个状态只会入队出队 1 1 1次,因此时间复杂度跟状态数量有关,为 O ( n × m × 2 p ) O(n\times m\times 2^p) O(n×m×2p)

代码实现

#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 12;
typedef pair<int, int> PII;
int n, m, p;
//g表示格子之间的状态:-1表示无障碍、0表示墙、k表示k类门
//key表示格子中的钥匙类型
int g[N][N], key[N];
int dis[N][1 << M]; //状态
bool st[N][1 << M]; //标记数组
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int get(int x, int y) //获取格子的编号
{return (x - 1) * m + y;
}
int bfs()
{memset(dis, 0x3f, sizeof dis);int z = get(1, 1), state = key[z]; //起点编号和状态queue<PII> q; //队列存点的编号和钥匙状态dis[z][state] = 0, st[z][state] = true;q.push({z, state});while(q.size()){PII p = q.front(); q.pop();int z1 = p.first, state = p.second;if(z1 == n * m) return dis[z1][state]; //走到终点int x = (z1 - 1) / m + 1, y = (z1 - 1) % m + 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 > m) continue;//转移到编号为z2的格子,z2号格子的钥匙状态为s,两个格子的状态为kint z2 = get(a, b), s = key[z2], k = g[z1][z2]; if(k == 0) continue; //有墙if(k >= 1 && !(state >> k & 1)) continue; //有门,没有钥匙s |= state;if(!st[z2][s]){dis[z2][s] = dis[z1][state] + 1, st[z2][s] = true;q.push({z2, s});}}}return -1;
}
int main()
{cin >> n >> m >> p;int K, S;cin >> K;memset(g, -1, sizeof g); //初始化两个格子之间的状态,-1表示无障碍while(K --) //输入门和墙{int x1, y1, x2, y2, k;cin >> x1 >> y1 >> x2 >> y2 >> k;int z1 = get(x1, y1), z2 = get(x2, y2);g[z1][z2] = g[z2][z1] = k; //k为0表示墙、否则k表示k类门}cin >> S;while(S --){int x, y, k;cin >> x >> y >> k;int z = get(x, y);key[z] |= 1 << k; //一个格子可能存在多把钥匙}cout << bfs() << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/3793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

架构师的六大生存法则与价值创造

目录 什么影响架构的成败 架构师的六大生存法则 一、所有的架构规划必须有且只有一个正确的目标 二、架构活动需要尊重和顺应人性 三、架构活动在有限的资源下最大化商业价值 四、架构师要考虑依赖的商业模块和技术生命周期 五、架构师为什么要关注技术体系的外部适应性…

【DINO】环境配置

1. DINO简介 作为一款基于Transformer性能强劲的计算机视觉算法&#xff0c;一经发布即受追捧&#xff0c;本文记录下在DINO官方代码在集群上的环境配置及训练自己的数据集过程。 DINO原文&#xff1a;https://arxiv.org/abs/2203.03605 DINO源代码&#xff1a;https://github.…

2021长城杯(部分复现)

2021年4月25日&#xff0c;上午8点左右&#xff0c;警方接到被害人金某报案&#xff0c;声称自己被敲诈数万元&#xff1b;经询问&#xff0c;昨日金某被嫌疑人诱导裸聊&#xff0c;下载了某“裸聊”软件&#xff0c;导致自己的通讯录和裸聊视频被嫌疑人获取&#xff0c;对其进…

Oracle数据库的AI能力分析,释放企业数据价值

解锁Oracle数据库的AI潜力 Oracle数据库提供了一系列的AI能力&#xff0c;旨在帮助企业和开发者更高效地利用人工智能技术。以下是Oracle数据库AI能力的一些关键点&#xff1a;1. AI向量相似性搜索&#xff1a;Oracle Database 23c引入了AI Vector Search功能&#xff0c;该功…

看企业中很多老师傅都说没前途,该不该放弃嵌入式单片机行业?

在企业中&#xff0c;我们经常会听到很多老师傅感叹嵌入式单片机行业没有前途&#xff0c;这也让不少人陷入了迷茫&#xff0c;不知道该不该放弃这个行业。其实&#xff0c;我发现很多新手在嵌入式和单片机领域都存在一个误区&#xff0c;那就是他们过于专注于工作技能的提升&a…

Win10装机(EasyU优启通制作优盘装机)

文章目录 EasyU优启通制作U盘WIndow 10 环境下载将Win10环境放在C盘之外的磁盘目录下&#xff0c;如D:/ 安装1. 进入BIOS2. 格式化C盘3. WinNTSetup4. 设置5.就绪&#xff1f;无需其他选项开始即可6. 重启&#xff0c;拔出U盘&#xff0c;就将自动安装6. 安装好后配置即可 参考…

C++中的queue(容器适配器)

目录 一、成员函数 一、构造函数 二、入栈 push 三、出栈 pop 四、判空 empty 五、队列大小 size 六、取队头元素 front 七、取队尾元素 back 八、入栈 emplace 九、交换函数 swap 二、非成员函数重载 一、关系运算符重载 二、交换函数 swap C中的queue不再是容…

JUC之线程、线程池

一、start与run方法 start方法开启一个新线程&#xff0c;异步执行。 run方法同步执行&#xff0c;不会产生新的线程。 start方法只能执行一次&#xff0c;run方法可以执行多次。 二、一些方法 sleep() 线程睡眠 两种方式调用&#xff1a; Thread.sleep(1000);TimeUnit.…

SAP MRP中的滚动提前期简介(MRP自动删除已固定计划订单)

通常被标记了固定标识的计划订单在运行MRP的时候系统是不会自动删除这部分计划订单的,但是SAP提供了“滚动提前期”这一功能,允许我们通过设定规则,在MRP运算的同时,自动删除在规定期间范围内的被固定的计划订单,从而避免这种干扰MRP运算的现象发生。 下面我们模拟这个场…

SignalR中的重连机制和心跳监测机制详解

一. 重连机制 声明&#xff1a;   本节仅介绍重连机制和心跳监测机制&#xff0c;基于Core 3.1框架&#xff0c;至于SignalR其它的一些基本使用&#xff0c;包括引入、Hub、配置等常规操作&#xff0c;在本节中不介绍&#xff0c;后续写Core下的SignalR 说明   默认是没有重…

钥匙和房间

题目链接 钥匙和房间 题目描述 注意点 所有 rooms[i] 的值 互不相同如果能进入所有房间返回true&#xff0c;否则返回falserooms[i] 是进入 i 号房间可以获得的钥匙集合 解答思路 可以通过深度优先遍历找到所有可以访问的房间&#xff0c;需要注意的是同一个房间不能重复访…

2024.4.26

//异或 Complex Complex::operator^(const Complex c1){Complex temp;temp.relthis->rel^c1.rel;temp.virthis->vir^c1.vir;return temp; }//按位取反 Complex Complex::operator~(){this->rel~this->rel;this->vir~this->vir;return* this; } //左移 Comple…

vue+element之解决upload组件上传文件失败后仍显示在列表上、自动上传、过滤、findIndex、splice、filter

MENU 前言错误案例(没有用)正确方法结束语 前言 el-upload上传失败后&#xff0c;文件仍显示在列表上。 这个pdf文件上传失败&#xff0c;仍显示在列表&#xff0c;给人错觉是上传成功&#xff0c;所以要把它去掉。 在element中&#xff0c;file-list和v-model:file-list是用于…

Bun 入门到精通(一)

Bun 是什么&#xff1f; Bun 是用于 JavaScript 和 TypeScript 应用程序的多合一工具包。它作为一个名为 bun 的可执行文件提供。 其核心是 Bun 运行时&#xff0c;这是一个快速的 JavaScript 运行时&#xff0c;旨在替代 Node.js。它是用 Zig 编写的&#xff0c;并由 JavaSc…

Matlab|交直流系统潮流计算(含5种控制模式)

目录 1 主要内容 程序参考流程图 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考文献《交直流系统潮流计算及相互关联特性分析》&#xff0c;采用5种交直流潮流控制方式&#xff1a;1.定电流定电压 2.定电流定熄弧角 3.定功率定电压 4.定功率定熄弧角 5.定触发角…

Kafka 生产者应用解析

目录 1、生产者消息发送流程 1.1、发送原理 2、异步发送 API 2.1、普通异步发送 2.2、带回调函数的异步发送 3、同步发送 API 4、生产者分区 4.1、分区的优势 4.2、生产者发送消息的分区策略 示例1&#xff1a;将数据发往指定 partition 示例2&#xff1a;有 key 的…

经典的免费wordpress模板

这款经典的免费WordPress模板以鲜艳的红色为主调&#xff0c;充满了活力与热情。设计简洁而现代&#xff0c;适合各种类型的项目网站。模板采用响应式设计&#xff0c;确保在不同设备和屏幕尺寸上都能呈现出完美的视觉效果。 红色象征着激情、活力和自信&#xff0c;这款模板…

2024年Q1企业邮箱安全性研究报告:钓鱼邮件同比增长59.9%

4月23日&#xff0c;Coremail邮件安全联合北京中睿天下信息技术有限公司发布《2024年第一季度企业邮箱安全性研究报告》。对当前企业邮箱的应用状况和安全风险进行了分析。 1、垃圾邮件持续增长 根据Coremail邮件安全人工智能实验室最新数据显示&#xff0c;2024年第一季度&am…

4 -26

4-26 1 英语单词100个一篇六级翻译 2 div 4 补题目 3 概率论期中卷子一张&#xff0c;复习复习。 4 备课ing 晚上出去炫饭&#xff0c;串串香&#xff0c;无敌了。 中间一些模拟题是真的恶心&#xff0c;思维题是真的想不到&#xff0c;感觉自己就是一个废物呢。 1.是将一个数…

[C++]STL---unordered_set与unordered_map的模拟实现

目录 前言 哈希桶的改造 哈希桶的初步改造 迭代器的模拟实现 operator() 类互相typedef时的前置声明 友元声明 迭代器的出口 插入Insert() 查找Find(&#xff09; 哈希表的最终改造 unordered_set的模拟实现 unordered_map的模拟实现 前言 unordered_set与set的区…