Acwing 1131.拯救大兵瑞恩(拆点)

简介: 笔记

AcWing 1131. 拯救大兵瑞恩

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


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


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


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


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


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


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


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


迷宫只有一个入口,在西北角。


也就是说,麦克可以直接进入 (1,1)单元。


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


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


输入格式

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


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

16.png

输出格式

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

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


数据范围


17.png


思路

分层图最短路。将每个点划分为几个状态,状态的划分由走到当前点拥有哪些钥匙决定。


d[i][j] 表示走到 i 这个点且当前拥有钥匙的状态为 j 的最短距离。


每次bfs 到一个新的点时,判断点之间是否有门, 如果有的话是否有钥匙,然后如果能通过的话,更新邻点的最短距离。


如果当前走到的点有钥匙因为捡钥匙代价为0,所以能捡就捡,并且更新下拥有的钥匙的状态。


代码

// Author:zzqwtcc
// Problem: C - Swiss-System Tournament
// Contest: AtCoder - Exawizards Programming Contest 2021(AtCoder Beginner Contest 222)
// Time:2021-10-09 20:00:14
// URL: https://atcoder.jp/contests/abc222/tasks/abc222_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
#include<unordered_map>
// #define int long long
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3f
#define mod 1000000007
#define MOD 998244353
#define rep(i, st, ed) for (int (i) = (st); (i) <= (ed);++(i))
#define pre(i, ed, st) for (int (i) = (ed); (i) >= (st);--(i))
#define debug(x,y) cerr << (x) << " == " << (y) << endl;
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
template<typename T> inline T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<typename T> inline T lowbit(T x) { return x & -x; }
// template<typename T> T qmi(T a, T b = mod - 2, T p = mod) { T res = 1; b %= (p - 1 == 0 ? p : p - 1); while (b) { if (b & 1) { res = (LL)res * a % p; }b >>= 1; a = (LL)a * a % p; }return res % mod; }
const int N = 90 + 10;
int n, m, p;
int mp[20][20];
vector<PII>vec[110];
set<PII>edges;
int key[105];
bool vis[105][1 << 10 + 1];
int d[105][1 << 10 + 1];
int dx[] = { 0,1,0,-1 }, dy[] = { 1,0,-1,0 };
void build() {
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            for (int k = 0; k < 4; ++k) {
                int x = i + dx[k];
                int y = j + dy[k];
                if (!x || x > n || !y || y > m)continue;
                if (edges.count({ mp[i][j],mp[x][y] }) == 0) {
                    vec[mp[i][j]].push_back({ mp[x][y],0 });
                }
            }
        }
    }
}
int bfs() {
    deque<PII>q;
    q.push_back({ 1,0 });
    memset(vis, 0, sizeof vis);
    memset(d, 0x3f, sizeof d);
    d[1][0] = 0;
    while (q.size()) {
        auto t = q.front();
        q.pop_front();
        if (vis[t.first][t.second])continue;
        vis[t.first][t.second] = true;
        //因为是 bfs 所以第一次遍历到当前点就是其最短距离
        if (t.first == n * m)return d[t.first][t.second];
        // 如果当前点有钥匙,因为捡钥匙是没有花费的,所以能捡就捡
        if (key[t.first]) {
            // 更新拥有钥匙的状态
            int state = t.second | key[t.first];
            // 更新新状态的最短距离
            if (d[t.first][state] > d[t.first][t.second]) {
                d[t.first][state] = d[t.first][t.second];
                q.push_front({ t.first,state });
            }
        }
        // 遍历当前点能到的所有点
        for (int i = 0; i < vec[t.first].size(); ++i) {
            int j = vec[t.first][i].first; // 邻点的编号
            int m = vec[t.first][i].second;// 与邻点之间是否有不可通过的门
            // 如果有且没有打开这扇门的钥匙,就 continue
            if (m && !(t.second >> m & 1))continue;
            // 更新当前点的最短距离
            if (d[j][t.second] > d[t.first][t.second] + 1) {
                d[j][t.second] = d[t.first][t.second] + 1;
                q.push_back({ j,t.second });
            }
        }
    }
    return -1;
}
void solve() {
    cin >> n >> m >> p;
    int t = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            mp[i][j] = ++t;
        }
    }
    int k; cin >> k;
    while (k--) {
        int x1, y1, x2, y2, g; cin >> x1 >> y1 >> x2 >> y2 >> g;
        int a = mp[x1][y1], b = mp[x2][y2];
        edges.insert({ a,b });
        edges.insert({ b,a });
        if (g) {
            vec[a].push_back({ b,g });
            vec[b].push_back({ a,g });
        }
    }
    build();
    int s; cin >> s;
    while (s--) {
        int x, y, q; cin >> x >> y >> q;
        key[mp[x][y]] |= 1 << q;
    }
    cout << bfs() << endl;
}
signed main() {
    //int _; cin >> _;
    //while (_--)
    solve();
    return 0;
}





目录
相关文章
|
调度 弹性计算 存储
拆解超算上云的障碍,阿里云用了这三招|E-HPC如何改变云超算?
2019年阿里云上海峰会,由阿里云资深技术专家何万青带来以“阿里云超算E-HPC平台”为题的演讲。本文内容包括了HPC概念及发展趋势,面向“大计算”设计的弹性基础设施,客户应用云上优化,着重介绍了E-HPC自动伸缩,闲时计算方案与混合云,数据全流程可视化以及HPC工作流与数据迁移等。
2092 0
|
Web App开发 JavaScript 前端开发
Python 自动化 - 浏览器chrome打开F12开发者工具自动Paused in debugger调试导致无法查看网站资源问题原因及解决方法,javascript反调试问题处理实例演示
Python 自动化 - 浏览器chrome打开F12开发者工具自动Paused in debugger调试导致无法查看网站资源问题原因及解决方法,javascript反调试问题处理实例演示
974 0
Python 自动化 - 浏览器chrome打开F12开发者工具自动Paused in debugger调试导致无法查看网站资源问题原因及解决方法,javascript反调试问题处理实例演示
|
6月前
|
人工智能 搜索推荐 数据挖掘
生成式人工智能认证(GAI认证)如何推动就业市场的创新?
生成式人工智能(Generative AI)认证是由全球终身学习公司Pearson推出,旨在为职场人士和学生提供全面的Gen AI技能培训。该认证涵盖方法论、提示优化、基础提示工程及伦理法律等内容,推动就业市场变革,拓展职业领域,升级技能要求,创新工作模式。尽管面临技术更新等挑战,但通过及时调整与培训,可保障就业市场健康发展,创造更多新兴岗位。
|
10月前
|
调度 云计算 芯片
云超算技术跃进,阿里云牵头制定我国首个云超算国家标准
近日,由阿里云联合中国电子技术标准化研究院主导制定的首个云超算国家标准已完成报批,不久后将正式批准发布。标准规定了云超算服务涉及的云计算基础资源、资源管理、运行和调度等方面的技术要求,为云超算服务产品的设计、实现、应用和选型提供指导,为云超算在HPC应用和用户的大范围采用奠定了基础。
179957 22
|
存储 缓存 算法
大文件 MD5 SHA 校验时间优化之路
【8月更文挑战第12天】处理大文件的MD5与SHA校验时,可通过选择高效算法实现、分块读取处理文件、利用多线程并行处理、采用硬件加速及缓存校验结果等方式优化校验时间。例如,使用性能良好的加密库如`pycryptodome`替代Python的标准`hashlib`库;分块读取文件并逐块计算哈希值,减少内存占用;利用多线程处理不同文件块;若条件允许,使用硬件加速如Intel AES-NI指令集;以及缓存重复校验的文件哈希值避免重算。这些策略可显著提高校验速度和系统效率。
920 1
|
消息中间件 存储 关系型数据库
实时计算 Flink版产品使用问题之同步时,上游批量删除大量数据(如20万条),如何提高删除效率
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
移动开发 网络协议 安全
一篇文章带你搞懂TCP/IP协议与OSI七层网络模型
一篇文章带你搞懂TCP/IP协议与OSI七层网络模型
597 0
一篇文章带你搞懂TCP/IP协议与OSI七层网络模型
|
JavaScript 前端开发 Go
【智能合约】Go语言调用以太坊 | geth
目录 1. geth 简介 1.1 下载地址: 1.2 安装: 1.3 查看是否安装成功 2. geth命令介绍 3. geth常用命令 3.1 指定数据目录 --datadir 3.2 账户相关 3.3 控制台console: 3.4 删除数据: 3.5 help 3.6 常见错误 4. Go语言调用合约 4.1 启动rpc端口 4.2 Go调用以太坊 4.3 调用接口 net_version net_listening net_peerCount eth接口 personal接口 db接口 最后
1256 0
【智能合约】Go语言调用以太坊 | geth
|
Unix
全网首发:configure: error: cannot guess build type; you must specify one
全网首发:configure: error: cannot guess build type; you must specify one
971 0
uniapp实现微信小程序横屏适配问题demo效果(整理)
uniapp实现微信小程序横屏适配问题demo效果(整理)