UVa The Morning after Halloween 万圣节后的早晨 双向BFS

news2024/12/24 9:08:38

题目链接:The Morning after Halloween
题目描述:

给定一个二维矩阵,图中有障碍物和字母,你需要把小写字母移动到对应的大写字母位置,不同的小写字母可以同时移动(上下左右四个方向或者保持不动 ),但是移动之后两个字母不能重合,同时移动后不能是两个字母发生了位置的交换。
在这里插入图片描述
上图给出了一种情况即该情况下的四种合法移动。
同时题目保证任意一个 2 × 2 2\times2 2×2的子区域中一定至少含有一个障碍物,同时边界一定是障碍物。

题解:

我们可以把每个矩阵的看成一个状态进行 B F S BFS BFS但是这样状态的个数比较多。
由于题目保证了很小的区域有障碍这也就变相说明了题目可以到达的点并不会很多,所以我们可以把每个可以经过的点进行编号,然后记录字母落在点的编号的三元组(缺少的字母用 0 0 0来表示,这意味着点的编号需要从 1 1 1开始),然后将三元组看成是状态,而每一次移动看成是一条边,这样我们只需要进行 B F S BFS BFS即可找到目标状态的最少移动次数(在移动的时候,我们需要判断是否违反规则,例如移动后两个字母在同一个位置,或者移动导致两个相邻的字母发生的交换)。由于本题的目标状态也是已知的,那么我们可以使用双向 B F S BFS BFS也就是从目标状态和初始状态同时进行 B F S BFS BFS当在中间的某个状态相遇的时候,就意味着找到了最少花费,在代码中我们只需要两个队列就可以实现双向 B F S BFS BFS一个放入初始状态进行搜索,一个放入目标状态进行搜索。
为什么需要双向 B F S BFS BFS?双向 B F S BFS BFS通常情况下能够让时间复杂度下降。原理实际上是因为每一次都选择含有较少的节点进行扩展,这样能一定程度上节省时间。
双向 B F S BFS BFS的代码应该是每次选择较小的队列进行扩展,而不是轮流进行扩展(如果是轮流进行扩展那么实际上和单向 B F S BFS BFS没有太大的差别)。

代码:

#include <bits/stdc++.h>

const int DIRECTION_NUM = 5;
const int MAXH = 16 + 1;
const int MAXW = 16 + 1;
const int MAX_NODE = MAXH * MAXW;

using namespace std;

int w, h, n, nodeNum;
char g[MAXH][MAXW];
int dx[] = {0, 1, -1, 0, 0};
int dy[] = {0, 0, 0, 1, -1};
vector<int> es[MAX_NODE];
int nodeId[MAXH][MAXW];
map<char, int> s, t;
int dis[MAX_NODE][MAX_NODE][MAX_NODE];
int inQ[MAX_NODE][MAX_NODE][MAX_NODE];

struct State
{
    int a, b, c; //最多三个字母位置的结点编号
    State() {}
    State(int a, int b, int c) : a(a), b(b), c(c) {}
    State& operator=(map<char, int> &rhs)
    {
        a = b = c = 0;
        auto iter = rhs.begin();
        for (size_t i = 0; i < n; i++) {
            if (i == 0) { a = iter->second; }
            else if (i == 1) { b = iter->second; }
            else if (i == 2) { c = iter->second; }
            iter++;
        }
        return *this;
    }
}st, ed;

void buildGraph()
{
    nodeNum = 1;
    s.clear();
    t.clear();
    for (int i = 0; i < MAX_NODE; i++) { es[i].resize(0); }
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (g[i][j] == '#') { continue; }
            nodeId[i][j] = nodeNum++;
            if (islower(g[i][j])) {
                s[g[i][j]] = nodeId[i][j];
            } else if (isupper(g[i][j])) {
                t[g[i][j]] = nodeId[i][j];
            }
        }
    }
    st = s;
    ed = t;
    es[0].push_back(0);
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (g[i][j] == '#') { continue; }
            for (int k = 0; k < DIRECTION_NUM; k++) {
                int nx = i + dx[k];
                int ny = j + dy[k];
                if (g[nx][ny] == '#') { continue; }
                es[nodeId[i][j]].push_back(nodeId[nx][ny]);
            }
        }
    }
}

bool conflict(int newA, int newB, int a, int b) { return (newA == newB && newA != 0) || (newA == b && newB == a && newA != 0 && newB != 0); }

int bfs(queue<State> &q, int nowQ)
{
    int size = q.size();
    int a, b, c;
    while(size--) {
        State now = q.front();
        q.pop();
        a = now.a, b = now.b, c = now.c;
        for (auto newA : es[a]) {
            for (auto newB : es[b]) {
                if (conflict(newA, newB, a, b)) { continue; }
                for (auto newC : es[c]) {
                    if (conflict(newA, newC, a, c) || conflict(newB, newC, b, c)) { continue; }
                    if (inQ[newA][newB][newC] == nowQ) { continue; }
                    if (inQ[newA][newB][newC] == 3 - nowQ) { // 在另一个队列中
                        cout << dis[newA][newB][newC] + dis[a][b][c] + 1 << endl;
                        return 0;
                    }
                    dis[newA][newB][newC] = dis[a][b][c] + 1;
                    inQ[newA][newB][newC] = nowQ;
                    q.push({newA, newB, newC});
                }
            }
        }
    }
    return -1;
}

void dBfs()
{
    queue<State> qs;
    queue<State> qt;
    memset(inQ, 0, sizeof(inQ));
    qs.push(st);
    qt.push(ed);
    dis[st.a][st.b][st.c] = 0;
    inQ[st.a][st.b][st.c] = 1;
    dis[ed.a][ed.b][ed.c] = 0;
    inQ[ed.a][ed.b][ed.c] = 2;
    while (!qs.empty() && !qt.empty()) {
        if (qs.size() < qt.size()) { // 优先选择队列短的队列进行bfs
            if(bfs(qs, 1) != -1) { return; }
        }
        else {
            if(bfs(qt, 2) != -1) { return; };
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin >> w >> h >> n) {
        if (w == 0 && h == 0 && n == 0) { break; }
        cin.get(); //读取末尾的换行
        for (int i = 0; i < h; i++) { cin.getline(g[i], MAXW); } // cin.getline读取的数据末尾没有'\n', cin.getline会保证末尾有结束符0,所以最多读取MAXW-1个有效字符
        buildGraph();
        dBfs();
    }
    return 0;
}

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

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

相关文章

概论_第8章_假设检验的基本步骤__假设检验的类型

一. 假设检验的基本步骤如下&#xff1a;第1步 根据实际问题提出原假设 及备择假设 , 要求 与 有且仅有一个为真&#xff1b;第2步 选取适当的检验统计量&#xff0c; 并在原假设 成立的条件下确定该检验统计量的分布&#xff1b;第3步 按问题的具体要求&#xff0c; 选取适当…

【java】OpenFeign源码解析学习

本文主要针对 spring-cloud-starter-openfeign 的 2.2.3.RELEASE 版本进行源码的解析。 OpenFeign是什么&#xff1f; 作为Spring Cloud的子项目之一&#xff0c;Spring Cloud OpenFeign以将OpenFeign集成到Spring Boot应用中的方式&#xff0c;为微服务架构下服务之间的调用提…

SQL Serve 日志体系结构

SQL Server 事务日志记录着 undo 及 redo 日志&#xff0c;为了保证数据库在崩溃后恢复&#xff0c;或者在正常数据库操作期间进行回滚&#xff0c;保证数据库事务完整性和持久化。如果没有事务日志记录&#xff0c;数据库在事务上将不一致&#xff0c;并且在数据库崩溃后可能导…

ThinkPHP5酒店预订管理系统

有需要请私信或看评论链接哦 可远程调试 ThinkPHP5酒店预订管理系统一 介绍 此酒店预订管理系统基于ThinkPHP5框架开发&#xff0c;数据库mysql&#xff0c;采用了ueditor富文本编辑器。系统角色分为用户&#xff0c;员工和管理员。用户可注册登录并预订酒店和评论等&#xff…

SpringCloud AlibabaSeata1.5.2的安装

目录 一、分布式问题 二、Seate简介 &#xff08;一&#xff09;官网 &#xff08;二&#xff09;Seate分布式事务的过程 &#xff08;三&#xff09; 分布式事务处理过程 &#xff08;四&#xff09;下载地址 三、Seata-Server安装 &#xff08;一&#xff09;官网 …

《Spring源码深度分析》第8章 数据库连接JDBC

目录标题前言一、数据库连接方式1.JDBC连接数据库2.Spring Jdbc连接数据库(JdbcTemplate)二、JdbcTemplate源码分析1.update/save功能的实现源码分析入口(关键)基础方法execute1.获取数据库连接池2.应用用户设定的输入参数3. 调用回调函数处理4. 资源释放Update中的回调函数2.q…

TreeSet 与 TreeMap And HashSet 与 HashMap

目录 Map TreeMap put()方法 : get()方法 : Set> entrySet() (重) : foreach遍历 : Set 哈希表 哈希冲突 : 冲突避免 : 冲突解决 ---- > 比散列(开放地址法) : 开散列 (链地址法 . 开链法) 简介 : 在Java中 , TreeSet 与 TreeMap 利用搜索树实现 Ma…

【项目精选】javaEE健康管理系统(论文+开题报告+答辩PPT+源代码+数据库+讲解视频)

点击下载源码 javaEE健康管理系统主要功能包括&#xff1a;教师登录退出、教师饮食管理、教师健康日志、体检管理等等。本系统结构如下&#xff1a; &#xff08;1&#xff09;用户模块&#xff1a; 实现登录功能 实现用户登录的退出 实现用户注册 &#xff08;2&#xff09;教…

运筹系列78:cbc使用介绍

1. 上手 1.1 快速使用 首先是简单的调用测试&#xff0c;在mac上首先安装clp的库&#xff1a;brew install coin-or-tools/coinor/cbc&#xff0c;然后新建项目进行调用&#xff0c;各项配置如下&#xff0c;注意要添加的library和directory比较多&#xff1a; 1.2 命令行方…

锁机制面试题

你是怎么理解乐观锁和悲观锁的&#xff0c;具体怎么实现呢&#xff1f; 悲观锁认为多个线程访问同一个共享变量冲突的概率较大 , 在每次访问共享变量之前都去真正加锁. 乐观锁认为多个线程访问同一个共享变量冲突的概率不大.,并不会真的加锁, 而是直接尝试访问数据 . 在访问的…

AcWing 165. 小猫爬山(DFS + 剪枝优化)

AcWing 165. 小猫爬山&#xff08;DFS 剪枝优化&#xff09;一、问题二、分析1、贪心想法的误区2、正解三、代码一、问题 二、分析 这道题其实总结下来&#xff0c;就是一句话&#xff0c;让更多的小猫坐在一辆车上&#xff0c;从而减少车的数量。 1、贪心想法的误区 这道题…

Spring Security in Action 第四章 SpringSecurity处理密码的相关讨论

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;以实战为线索&#xff0c;逐步深入SpringSecurity相关知识相关知识&#xff0c;打造完整的SpringSecurity学习步骤&#xff0c;提升工程化编码能力和思维能力&#xff0c;写出高质量代码。希望大家都能够从中有所收获&#…

Java面试——maven篇

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

以太坊数据开发-Web3.py-安装连接以太坊数据

Web3.py是连接以太坊的python库&#xff0c;它的API从web3.js中派生而来。如果你用过web3.js&#xff0c;你会对它的API很熟悉。但惭愧的是&#xff0c;作为一个以太坊上Dapp的开发者&#xff0c;我几乎没有直接使用过web3.js&#xff0c;也没有看过它的API。 官网&#xff1a…

STL——queue

一、queue介绍和使用 1.queue文档介绍 &#xff08;1&#xff09;队列是一种容器适配器&#xff0c;专门用于在FIFO上下文&#xff08;先进先出&#xff09;中操作&#xff0c;其中从容器的一端插入元素&#xff0c;另一端提取元素。 &#xff08;2&#xff09;队列是作为容…

ImageMagick任意文件读取漏洞(CVE-2022-44268)

0x00 前提 前几天爆出一个 ImageMagick 漏洞 &#xff0c;可以造成一个任意文件读取的危害比较可观&#xff0c;最近有时间来复现学习一下 主要是影响的范围很大&#xff0c;很多地方都有这个问题&#xff0c;需要来学习一下 0x01 介绍 ImageMagick 是一个免费的开源软件套…

【计组】设计大型DMP系统--《深入浅出计算机组成原理》(十四)

目录 一、DMP&#xff1a;数据管理平台 二、MongoDB 真的万能吗 三、关系型数据库&#xff1a;不得不做的随机读写 &#xff08;一&#xff09;Cassandra&#xff1a;顺序写和随机读 1、Cassandra 的数据模型 2、Cassandra 的写操作 3、Cassandra 的读操作 &#xff08…

Mysql 增删改查(一) —— 查询(条件查询where、分页limits、排序order by、分组 group by)

查询 select 可以认为是四个基本操作中使用最为频繁的操作&#xff0c;然而数据量比较大的时候&#xff0c;我们不可能查询所有内容&#xff0c;我们一般会搭配其他语句进行查询&#xff1a; 假如要查询某一个字段的内容&#xff0c;可以使用 where假如要查询前几条记录&#…

线上服务质量的问题该如何去处理?你有什么思路?

线上服务质量的问题该如何去处理&#xff1f;你有什么思路&#xff1f; 目录&#xff1a;导读 发现线上故障 处理线上故障 修复线上故障 运营线上质量 就是前几天有个同学问了我一个问题&#xff1a;目前业内高可用部署主要采用方案&#xff1f; 看到这个问题&#xff0c…

5G网络架构与组网部署

文章目录5G网络架构与组网部署一、5G网络架构的演进趋势5G移动通信系统4G移动通信系统二、核心网架构的演进三、无线接入网的演进趋势5G网络架构与组网部署 一、5G网络架构的演进趋势 5G移动通信系统 5G移动通信系统包括5GC(5G Corn Network,5G核心网)和NG-RAN(Next Generat…