UVa 1604 Cubic Eight-Puzzle 立体八数码问题 双向BFS 状态设定

news2025/7/19 8:09:14

题目链接:Cubic Eight-Puzzle
题目描述:

给定一个初始状态和一个终止状态的 3 ∗ 3 3*3 33网格,网格中含有 8 8 8个立方体和一个空白,每个立方体的颜色如下:
在这里插入图片描述
需要注意的是:只会给出终止状态的立方体的顶面朝向,而初始的立方体摆放方式如下图,其中空格位置由输入的两个整数决定:
在这里插入图片描述
你每次操作可以将初始状态的一个立方体推入到空白地方,推入过程中会发生旋转,过程如下图所示:

问能否 30 30 30步以内到达目标状态。

题解:

本题的思路很简单,我们可以使用双向 B F S BFS BFS,每个非空格方格有六种状态(分别对应六个面朝上),所以我们可以用一个四位的二进制来表示一共有九个网格所以需要 36 36 36位二进制来表示一种状态。由于目标状态的侧面不确定,所以每个侧面对应两种情况,我们需要初始将所有可能的目标状态放入队列中,然后从起始状态进行搜索即可,需要注意的是,双向 B F S BFS BFS应该每次选择较小的队列进行搜索,搜索的次数为选择队列当前的大小,而不是一个队列搜索到头。
这道题目的细节比较多,推旋转后的状态一定要仔细。
同时这道题用 S T L STL STL的话常数较大,很容易超时,需要注意。

代码:

#include <bits/stdc++.h>

const int MAXN = 9;

using namespace std;

typedef pair<int, long long> State;

int x, y, ans;
long long endStatus, initStatus;
long long status[MAXN];
string s[MAXN];
queue<State> q[2];
unordered_map<long long, int> inQ, dis;


void getStatus(string &s, vector<int> &status)
{
    if (s[0] == 'E') {
        status.push_back(0);
    } else if (s[0] == 'W') {
        status.push_back(1);
        status.push_back(2);
    } else if (s[0] == 'R') {
        status.push_back(3);
        status.push_back(4);
    } else if (s[0] == 'B') {
        status.push_back(5);
        status.push_back(6);
    }
}

void initEndStatus(int p)
{
    if (p == 9) {
        endStatus = 0;
        for (int i = 0; i < 9; i++) {
            endStatus |= status[i] << (4 * i);
        }
        inQ[endStatus] = 1;
        dis[endStatus] = 0;
        q[1].push({0, endStatus});
        return;
    }
    vector<int> v;
    getStatus(s[p], v);
    for (int nowStatus : v) {
        status[p] = nowStatus;
        initEndStatus(p + 1);
    }
}

long long getInitStatus()
{
    long long initStatus = 0;
    for (int i = 0; i < 9; i++) {
        if (i / 3 == x && i % 3== y) { continue; }
        initStatus |= 1LL << (4 * i);
    }
    return initStatus;
}

void init()
{
    while (!q[0].empty()) { q[0].pop(); }
    while (!q[1].empty()) { q[1].pop(); }
    inQ.clear();
    dis.clear();
    initStatus = getInitStatus();
    initEndStatus(0);
}

void getEmptyPos(long long status, int &x, int &y)
{
    for (int i = 0; i < 9; i++) {
        if (((status >> (4 * i)) & (0b1111)) == 0) {
            x = i / 3;
            y = i % 3;
            break;
        }
    }
}

// 获取x, y位置的状态
long long getStatus(long long status, int x, int y)
{
    return (status >> (4 * (3 * x + y))) & 0b1111;
}

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

long long p[7][4] = {
    {0, 0, 0, 0},
    {5, 5, 3, 3},
    {4, 4, 6, 6},
    {6, 6, 1, 1},
    {2, 2, 5, 5},
    {1, 1, 4, 4},
    {3, 3, 2, 2}
};

long long transfer(long long status, int i)
{
    int x = 0, y = 0;
    getEmptyPos(status, x, y);
    int nx = x + dx[i];
    int ny = y + dy[i];
    if (nx < 0 || nx > 2 || ny < 0 || ny > 2) { return -1; }
    int lasP = 3 * x + y;
    int newP = 3 * nx + ny;
    long long newStatus = status;
    newStatus ^= getStatus(status, nx, ny) << (4 * newP); // 将nx, ny变为空格
    newStatus |= p[getStatus(status, nx, ny)][i] << (4 * lasP); // 将x, y填入新的状态
    return newStatus;
}

int bfs(queue<State> &q, int nowQ)
{
    int size = q.size();
    while (size--) {
        State now = q.front();
        q.pop();
        if (now.first >= 30) { continue; }
        for (int i = 0; i < 4; i++) {
            State newState;
            newState.first = now.first + 1;
            newState.second = transfer(now.second, i);
            if (newState.second == -1) { continue; }
            if (inQ.count(newState.second)) {
                if (inQ[newState.second] == 1 - nowQ) {
                    ans = dis[newState.second] + now.first + 1;
                    if (ans > 30) { ans = -1; }
                    return 0;
                } else {
                    continue;
                }
            }
            dis[newState.second] = newState.first;
            inQ[newState.second] = nowQ;
            q.push(newState);
        }
    }
    return -1;
}

void dBfs()
{
    if (inQ.count(initStatus)) {
        ans = 0;
        return;
    }
    ans = -1;
    inQ[initStatus] = 0;
    dis[initStatus] = 0;
    q[0].push({0, initStatus});
    while (!q[0].empty() && !q[1].empty()) {
        if (q[0].size() <= q[1].size()) {
            if (bfs(q[0], 0) == 0) { return; }
        } else {
            if (bfs(q[1], 1) == 0) { return; }
        }
    }
}

int main()
{
    while (cin >> x >> y && (x != 0 || y != 0)) {
        x--;
        y--;
        swap(x, y); // 习惯横着编号
        for (int i = 0; i < 9; i++) { cin >> s[i]; }
        init();
        dBfs();
        cout << ans << endl;
    }
    return 0;
}

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

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

相关文章

Android init 进程流程分析 一

init 进程流程分析 一1.1引入init进程1.2 init 进程入口函数参考博客预告下一章 FirstStageMain()分析1.1引入init进程 1.启动电源以及系统启动&#xff1a; 上电引导芯片从预定义的地放&#xff08;固化在ROM)开始执行&#xff0c;加载引导程序Bootloader 到RAM中&#xff0c…

格雷码的实现

格雷码&#xff1a;任意两个相邻的二进制数之间只有一位不同 想必通信专业的学生应该都接触过格雷码&#xff0c;它出现在数电、通信原理等课程里。 如下图所示一个四位格雷码是什么样子的&#xff1a; 格雷码的特点&#xff1a; 其最大的特点是任意上下相邻的两个码值间&am…

css学习-----web

引入方式 内嵌式 css写在style标签中 外链式 css写在一个单独的.css文件中 <link rel"stylesheet" href"./文件名.css">stylesheet关系为样式表&#xff1b; href地址 行內式 css写在标签的style属性中 可以配合js使用 选择器 标签选择器是选…

CTFer成长之路之XSS的魔力

XSS的魔力CTF XSS闯关 题目描述: 你能否过关斩将解决所有XSS问题最终获得flag呢&#xff1f; docker-compose.yml version: "3.2"services:xss:image: registry.cn-hangzhou.aliyuncs.com/n1book/web-xss:latestports:- 3000:3000启动方式 docker-compose up -…

Spring依赖注入(四):Bean的循环依赖是如何产生和解决的?

前言其实这篇文章才是正主&#xff0c;前面几篇文章&#xff1a;Spring依赖注入&#xff08;一&#xff09;&#xff1a;字段注入的方式是如何工作的&#xff1f;Sprng依赖注入&#xff08;二&#xff09;&#xff1a;setter注入是如何工作的&#xff1f;Sprng依赖注入&#xf…

easyExcel与poi版本不兼容导致的后台报错问题

1、背景&#xff1a;最新接手公司系统excel导入解析模块&#xff0c;点击批量导入&#xff0c;后台报错如下 com.alibaba.excel.exception.ExcelAnalysisException: java.lang.NoClassDefFoundError: org/apache/poi/poifs/filesystem/FileMagicat com.alibaba.excel.analysis.…

CycleGAN代码使用入门

以下内容为本人亲测使用过程&#xff0c;完成了橘子到苹果的AI转化效果&#xff0c;先上效果&#xff1a; 1、下载数据集 Index of /cyclegan/datasets 本次做的是苹果和橘子相互转化的实验&#xff0c;所以下载apple2orange.zip数据集 2、下载代码 github地址为&#xff1a;…

ChatGPT从下游应用“火”到了上游芯片厂,国内谁将受益?

因库存陷入低迷周期的半导体市场近日因ChatGPT的火热而重新受到外界关注。 原文链接&#xff1a;ChatGPT从下游应用“火”到了上游芯片厂&#xff0c;国内谁将受益&#xff1f; 由于ChatGPT属于生成式AI&#xff0c;被誉为“AI芯片”第一股的英伟达应声而涨。2月13日收盘&#…

Go高质量编程与性能调优-学习笔记

1 高质量编程 1.1 简介 1.1.1 高质量代码 高质量代码即正确可靠、简洁清晰的代码 1.1.2 编程原则 简单性可读性生产力1.2 编码规范 1.2.1 代码格式 推荐gofmt自动格式化代码&#xff01; 推荐goimports实现gofmt依赖包管理&#xff01; 1.2.2 注释 注释要解释代码作用、…

5个设计师常用素材库

推荐5个设计素材网站&#xff0c;免费下载&#xff01; 1、菜鸟图库 菜鸟图库-免费设计素材下载 菜鸟图库是一个素材量非常丰富的网站&#xff0c;该网站聚合了平面、UI、淘宝电商、高清背景图、图片、插画等高质量素材。平面设计模板非常多&#xff0c;很多都能免费下载&…

springmvc实现controller接口

springmvc实现controller接口 前置配置 基础环境 springmvc 环境 jdk1.8 tomcat8.5 集成环境 ideasmart-tomcat (idea 中 tomcat插件) 实现controller接口 import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Control…

UNIAPP实战项目笔记59 NodeJS后端生成token 和 修复一些bug

UNIAPP实战项目笔记59 NodeJS后端生成token 和 修复一些bug 后端保持数据时往数据库写入token 修复一些前面遗留的问题bug 实际案例图片 后端接口文件 index.js var express require(express); var router express.Router(); var connection require(../db/sql.js); var us…

11、STM32通用定时器输出PWM

目录 1.通用定时器输出PWM 2.PWM的工作原理 3.PWM的内部运作机制 4.PWM的模式 41.边沿对齐模式 5.自动加载的预加载寄存器 6.定时器输出PWM结构体讲解 7.定时器输出PWM库函数讲解 8.定时器输出PWM----实战驱动SG90舵机 1.通用定时器输出PWM 以TIM3为例&#xff0c;STM…

makdown模版参考

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

一次性打包学透 Spring

不知从何时开始&#xff0c;Spring 这个词开始频繁地出现在 Java 服务端开发者的日常工作中&#xff0c;很多 Java 开发者从工作的第一天开始就在使用 Spring Framework&#xff0c;甚至有人调侃“不会 Spring 都不好意思自称是个 Java 开发者”。 之所以出现这种局面&#xf…

危害肠道健康的两大敌人:诺如病毒和轮状病毒

谷禾健康 // 近日&#xff0c;多地发生诺如病毒感染事件&#xff0c;诺如病毒引起的急性感染性腹泻进入发病高峰期。那么什么是诺如病毒&#xff1f;我们又该如何预防&#xff1f; 诺如病毒和轮状病毒都是传染性很强的肠道病毒&#xff0c;是导致急性胃肠炎的最重要原因之一。会…

如何自己搭建一个ai画图系统? 从0开始云服务器部署novelai

如何自己搭建一个ai画图系统&#xff1f; 从0开始云服务器部署novelai ​ 上面两张图都是通过ai生成的&#xff0c;是不是有以假乱真的感觉。 本教程提供的是自己搭建一个可以外网访问的ai系统的方法&#xff0c;需要采购gpu服务器&#xff08;后续会出白嫖的方式&#xff09;&…

Java俄罗斯方块游戏

技术&#xff1a;Java等摘要&#xff1a;俄罗斯方块是一款十分经典的游戏&#xff0c;它的主要运行规律为对系统随机产生的图形进行上下左右移动、旋转等操纵&#xff0c;使之排列成完整的一行或多行并且消除得分。它上手容易&#xff0c;难度循序渐进&#xff0c;老少皆宜&…

Android 架构 MVC MVP MVVM,这一波你应该了然于心

MVC&#xff0c;MVP和MVVM是软件比较常用的三种软件架构&#xff0c;这三种架构的目的都是分离&#xff0c;避免将过多的逻辑全部堆积在一个类中。在Android中&#xff0c;Activity中既有UI的相关处理逻辑&#xff0c;又有数据获取逻辑&#xff0c;从而导致Activity逻辑复杂不单…

Android入门第66天-使用AOP

开篇这篇恐怕又是一篇补足网上超9成关于这个领域实际都是错的、用不起来的一个知识点了。网上太多太多教程和案例用的是一个叫hujiang的AOP组件-com.hujiang.aspectjx:gradle-android-plugin-aspectjx。首先这些错的文章我不知道是怎么来的&#xff0c;其次那些案例真的运行成功…