【HDU-1043】Eight 八数码(BFS之A*算法)

Eight(八数码)

Vjudge链接

题目描述

15 块拼图已有 100 多年的历史,即使你不知道它的名字,也一定见过它。它由 15 块滑动瓷砖组成,每块瓷砖上都有一个从 1 到 15 的数字,所有瓷砖都被装在一个 4×4 的框架内,其中缺少一块瓷砖。我们把这块缺失的瓷砖称为 “x”;谜题的目的是将瓷砖排列成以下顺序:

 1  2  3  45  6  7  89 10 11 12
13 14 15  x

其中唯一合法的操作是将 "x "与与它共享一条边的其中一块牌交换。举例来说,下面的移动顺序可以解决一个略微混乱的谜题:

 1  2  3  4     1  2  3  4     1  2  3  4     1  2  3  45  6  7  8     5  6  7  8     5  6  7  8     5  6  7  89  x 10 12     9 10  x 12     9 10 11 12     9 10 11 12
13 14 11 15    13 14 11 15    13 14  x 15    13 14 15  xr->            d->            r->

上一行中的字母表示每一步中 "x "与 "x "的哪一个相邻棋子进行了交换;合法值分别为 “r”、“l”、"u "和 “d”,代表右、左、上和下。

并不是所有的谜题都能被解开;1870 年,一个名叫山姆-洛伊德的人因为分发了一个无法解开的谜题版本而出名,让很多人感到沮丧。
让很多人感到沮丧。事实上,要把一道普通的谜题变成一道无解的谜题,只需要交换两块牌(当然,缺失的 "x "牌不算在内)。

在这个问题中,你将编写一个程序来解决不太为人所知的 8 字谜排列。

输入:

您将收到几种关于 "8 "字谜题配置的说明。其中一种描述仅仅是一张牌子初始位置的列表,行列从上到下依次排列,每一行中的牌子从左到右依次排列,牌子用数字1到8加上 "x "来表示。例如,这道谜题

1 2 3
x 4 6
7 5 8

就是用这个列表来描述的:

1 2 3 x 4 6 7 5 8

输出:

如果谜题无解,您将在标准输出中打印 “unsolvable”(无解)字样,或者打印一个完全由字母 “r”、“l”、"u "和 "d "组成的字符串,描述一系列产生解的棋步。字符串不得包含空格,并从行首开始。不要在每种情况之间打印空行。

输入样例:

2  3  4  1  5  x  7  6  8

输出样例:

ullddrurdllurdruldr

题意

给定一个九方格,每个方格都有一个数字,分别是 1 ∼ 8 1∼8 18 和一个 x ,规定可以把 x 与其上、下、左、右四个方向之一的数字进行交换(如果存在)。要求我们通过交换,使得网格变为如下排列:

1 2 3
4 5 6
7 8 x

不过,题目是以字符串的形式给出初始状态,也就是说,我们最终需要达到

1 2 3 4 5 6 7 8 x

的状态,如果可以则输出每一步的操作步骤,否则输出 “unsolvable”。

思路

这里使用 A* 算法解决,相关学习可转至:Introduction to the A* Algorithm

首先要知道八数码有解的条件,可参考:八数码问题有解的条件及其推广

将八数码原本的二维形式转化为一维形式,求出所有的逆序对,当逆序对的数量为偶数时,有解,否则无解。

设估价函数 f() 为当前点的状态与目标状态的曼哈顿距离之和,

因为 A* 算法要求 当前状态的真实距离 + 到终点的估计距离 <= 起点到终点的真实距离 ,所以我们可以用优先队列存储每次的状态,保证终点在第一次出队时即为最优解。同时用 prev 记录每次的操作和上一步状态,方便最后回推输出操作路径。

详细见代码↓

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <unordered_map>
#define PIS pair<int, string>using namespace std;int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
char op[5] = "urdl";// 从该状态到达目标状态的估价函数
// 计算各个点与目标状态的曼哈顿距离之和
int f(string state)
{int res = 0;for (int i = 0; i < state.size(); i++){if (state[i] != 'x'){int t = state[i] - '1';res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);}}return res;
}string bfs(string start)
{string end = "12345678x";unordered_map<string, int> dist;unordered_map<string, pair<string, char>> prev; // 记录到达此状态的操作和上一步状态// 初始化小根堆// 第一元素:从起点到该状态的真实距离+该状态到目标状态的估价距离// 第二元素:存储该状态priority_queue<PIS, vector<PIS>, greater<PIS>> heap;heap.push({f(start), start});dist[start] = 0;while (heap.size()){auto t = heap.top();heap.pop();string state = t.second;if (state == end) break;// 求'x'的坐标int x, y;for (int i = 0; i < state.size(); i++){if (state[i] == 'x'){x = i / 3, y = i % 3;break;}}int step = dist[state];  // 记录原来到达该状态的距离string source = state;   // 存储备份该状态for (int i = 0; i < 4; i++){int xx = x + dx[i], yy = y + dy[i];if (xx >= 0 && xx < 3 && yy >= 0 && yy < 3){swap(state[x * 3 + y], state[xx * 3 + yy]);  // 交换if (!dist.count(state) || dist[state] > step + 1){dist[state] = step + 1;prev[state] = {source, op[i]};heap.push({dist[state] + f(state), state});}swap(state[x * 3 + y], state[xx * 3 + yy]);  // 恢复}}}// 回推路径string res;while (end != start){res += prev[end].second;end = prev[end].first;}reverse(res.begin(), res.end());return res;
}int main()
{string g, c, seq;while (cin >> c){g += c;if (c != "x") seq += c;}// 记录逆序对的对数// 如果逆序对的数量是偶数,那就一定有解int cnt = 0;  for (int i = 0; i < seq.size(); i++){for (int j = i + 1; j < seq.size(); j++){if (seq[i] > seq[j])cnt++;}}if (cnt % 2) puts("unsolvable");else cout << bfs(g) << endl;return 0;
}

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

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

相关文章

【论文阅读24】Better Few-Shot Text Classification with Pre-trained Language Model

论文相关 论文标题&#xff1a;Label prompt for multi-label text classification&#xff08;基于预训练模型对少样本进行文本分类&#xff09; 发表时间&#xff1a;2021 领域&#xff1a;多标签文本分类 发表期刊&#xff1a;ICANN&#xff08;顶级会议&#xff09; 相关代…

基于opencv的几种图像滤波

一、介绍 盒式滤波、均值滤波、高斯滤波、中值滤波、双边滤波、导向滤波。 boxFilter() blur() GaussianBlur() medianBlur() bilateralFilter() 二、代码 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> …

2023爱分析·低代码厂商全景报告|爱分析报告

关键发现 低代码开始向甲方核心场景渗透&#xff0c;呈现两个显著特征&#xff1a;“更深入”、“更垂直”。更深入&#xff0c;即甲方愈发注重低代码在复杂业务场景的应用开发能力&#xff1b;更垂直&#xff0c;即甲方需要使用低代码开发行业垂直应用&#xff0c;因此对行业或…

springboot项目实现验证码功能(短信防刷机制实现)

为什么写这篇文章 项目里面有用到用户手机号注册发短信功能&#xff0c;需要做短信防刷机制。主要验证逻辑如下 图形验证码验证IP验证&#xff0c;同一个IP每日限制发送20条发送时判断5分钟之内是否发送了验证码&#xff0c;如果有的话就发送重复的至用户手机&#xff0c;减少…

JDBC的书写

文章目录 基本概念操作数据库方式一&#xff08;不建议使用这种查询&#xff0c;可以sql注入&#xff09;读取properties文件 事务转账示例 获取id连接池 基本概念 持久化:把数据放在磁盘上&#xff0c;断电后还是有数据。使用execute 执行增删改返回false,查返回true 操作数…

AI 绘画Stable Diffusion 研究(三)sd模型种类介绍及安装使用详解

本文使用工具&#xff0c;作者:秋葉aaaki 免责声明: 工具免费提供 无任何盈利目的 大家好&#xff0c;我是风雨无阻。 今天为大家带来的是 AI 绘画Stable Diffusion 研究&#xff08;三&#xff09;sd模型种类介绍及安装使用详解。 目前&#xff0c;AI 绘画Stable Diffusion的…

css3 hover border 流动效果

/* Hover 边线流动 */.hoverDrawLine {border: 0 !important;position: relative;border-radius: 5px;--border-color: #60daaa; } .hoverDrawLine::before, .hoverDrawLine::after {box-sizing: border-box;content: ;position: absolute;border: 2px solid transparent;borde…

生成对抗网络DCGAN学习实践

在AI内容生成领域&#xff0c;有三种常见的AI模型技术&#xff1a;GAN、VAE、Diffusion。其中&#xff0c;Diffusion是较新的技术&#xff0c;相关资料较为稀缺。VAE通常更多用于压缩任务&#xff0c;而GAN由于其问世较早&#xff0c;相关的开源项目和科普文章也更加全面&#…

【机器学习】Gradient Descent

Gradient Descent for Linear Regression 1、梯度下降2、梯度下降算法的实现(1) 计算梯度(2) 梯度下降(3) 梯度下降的cost与迭代次数(4) 预测 3、绘图4、学习率 首先导入所需的库&#xff1a; import math, copy import numpy as np import matplotlib.pyplot as plt plt.styl…

Devops系统中jira平台迁移

需求:把aws中的devops系统迁移到华为云中,其中主要是jira系统中的数据迁移,主要方法为在华为云中建立一套 与aws相同的devops平台,再把数据库和文件系统中的数据迁移,最后进行测试。 主要涉及到的服务集群CCE、数据库mysql、弹性文件服务SFS、数据复制DRS、弹性负载均衡ELB。 迁…

问道管理:补仓什么意思?怎么补仓可以降低成本?

补仓这个术语我们在理财出资中经常听到&#xff0c;例如基金补仓&#xff0c;股票补仓。那么&#xff0c;补仓什么意思&#xff1f;怎样补仓能够降低成本&#xff1f;问道管理为我们预备了相关内容&#xff0c;以供参阅。 补仓什么意思&#xff1f; 股票补仓是指出资者在某一只…

Debian 12.1 “书虫 “发布,包含 89 个错误修复和 26 个安全更新

导读Debian 项目今天宣布&#xff0c;作为最新 Debian GNU/Linux 12 “书虫 “操作系统系列的首个 ISO 更新&#xff0c;Debian 12.1 正式发布并全面上市。 Debian 12.1 是在 Debian GNU/Linux 12 “书虫 “发布六周后推出的&#xff0c;目的是为那些希望在新硬件上部署操作系统…

Java学习一 --- Java简介

Java是一种高级编程语言&#xff0c;由Sun Microsystems创建并于1995年发布。它是一种面向对象的语言&#xff0c;被广泛应用于Web、移动设备、桌面应用程序、游戏、数据库等领域。Java具有跨平台特性&#xff0c;即一次编写&#xff0c;多平台运行&#xff0c;所以它也被称为“…

Vivado进行自定义IP封装

一. 简介 本篇文章将介绍如何使用Vivado来对上篇文章(FPGA驱动SPI屏幕)中的代码进行一个IP封装&#xff0c;Vivado自带的IP核应该都使用过&#xff0c;非常方便。 这里将其封装成IP核的目的主要是为了后续项目的调用&#xff0c;否则当我新建一个项目的时候&#xff0c;我需要将…

探讨未来的法规变革:以算法备案为例

在进入科技高速发展的二十一世纪&#xff0c;越来越多的公司、组织和个人开始采用复杂的算法来优化决策、提升生产力并开创创新。同时&#xff0c;对这些算法的治理、监管和备案也成为了社会关注的焦点。本文将尝试探讨未来算法备案的法规变革&#xff0c;以期给予所有与此相关…

VirtualBox Ubuntu无法安装增强功能以及无法复制粘贴踩坑记录

在VirtualBox安装增强功能想要和主机双向复制粘贴&#xff0c;中间查了很多资料&#xff0c;终于是弄好了。记录一下过程&#xff0c;可能对后来人也有帮助&#xff0c;我把我参考的几篇主要的博客都贴上来了&#xff0c;如果觉得我哪里讲得不清楚的&#xff0c;可以去对应的博…

Shell脚本学习-Shell函数

函数的作用就是将程序里多次被调用的相同代码组合起来&#xff08;函数体&#xff09;&#xff0c;并为其取一个名字&#xff0c;即函数名。其他所有想重复调用这部分代码的地方都只需要调用这个名字就可以了。当需要修改这部分代码时候&#xff0c;只需要修改函数体内的这部分…

NOI2023 打金记

Day -4 最后一场模拟赛&#xff0c;肯定要用力打啊&#xff01; 然而一题不会&#xff0c;呜呜呜。 于是开始拼暴力&#xff0c;写了 90 60 60 210 90 60 60 210 906060210&#xff0c;结果挂成 40 60 60 160 40 60 60 160 406060160。 T1 我将题目转化为&am…

【简单认识GFS分布式文件系统】

文章目录 一.GlusterFS 概述1.GlusterFS简介2.特点3.GlusterFS 术语4.模块化堆栈式架构5.GlusterFS 的工作流程6.GlusterFS的卷类型1、**分布式卷&#xff08;Distribute volume&#xff09;**2、条带卷&#xff08;Stripe volume&#xff09;3、复制卷&#xff08;Replica vol…

JS检测属性位于对象本身还是来自于其原型链

学习原型链时有这个疑问&#xff0c;之前查过了但是老是忘记&#xff0c;现在记录一下&#xff0c;避免忘记。 参考&#xff1a;https://blog.csdn.net/weixin_40920953/article/details/88295651 1.in操作符 in 操作符会在通过对象能够访问给定属性时返回true&#xff0c;无…