洛谷P1379 八数码难题【A-star】

P1379 八数码难题

八数码难题首先要进行有解性判定,避免无解情况下盲目搜索浪费时间。

有解性判定

P10454 奇数码问题

题意简述

在一个 n × n n \times n n×n 的网格中进行,其中 n n n 为奇数, 1 1 1 个空格和 [ 1 , n 2 − 1 ] [1,n^2 - 1] [1,n21] n 2 − 1 n^2 - 1 n21 个数不重不漏地分布在网格中。空格可与上下左右的数字交换位置。现给定两个奇数码游戏的局面,判定是否存在一种移动空格的方式使得互相可达。

实际上,八数码问题就是一个 n = 3 n = 3 n=3 的奇数码游戏。

思路

将网格图转为长为 n 2 − 1 n^2 - 1 n21 的一维序列,例如:

5 2 8
1 3 _
4 6 7

可记为 5 , 2 , 8 , 1 , 3 , 4 , 6 , 7 5 ,2,8,1,3,4,6,7 5,2,8,1,3,4,6,7 ,忽略空格。可以发现:若左右移动空格,该序列不变;若上下移动空格,例如:

5 2 _
1 3 8
4 6 7

序列变为 5 , 2 , 1 , 3 , 8 , 4 , 6 , 7 5,2,1,3,8,4,6,7 5,2,1,3,8,4,6,7 ,相当于把 8 8 8 往前移动了 n − 1 = 2 n - 1 = 2 n1=2 位,有两个数字到了 8 8 8 的后面,那么这两个数字中,原来与 8 8 8 形成逆序对的变成了非逆序对,原来与 8 8 8 形成非逆序对的变成了逆序对。

进一步思考:

1.若在位置发生变动的数中原有奇数个逆序对,由于 n − 1 n - 1 n1 是偶数,那么原来也有奇数个非逆序对,因此交换后逆序对的个数仍为奇数;

2.若在位置发生变动的数中原有偶数个逆序对,由于 n − 1 n - 1 n1 是偶数,那么原来也有偶数个非逆序对,因此交换后逆序对的个数仍为偶数。

综上所述,无论怎么交换,逆序对个数的奇偶性不变,因此可以比较初状态和末状态的逆序对(用树状数组统计)奇偶性是否相同,方可判定是否有解。

代码实现

注意 0 0 0 不参与统计,忘了这一点会 WA。

#include <bits/stdc++.h>using namespace std;int n;int lowbit(int p){return p & (-p);}void insert(int p,int x,vector <int>& c){for(;p <= n;p += lowbit(p))c[p] += x;
} int query(int p,vector <int>& c){int sum = 0;for(;p;p -= lowbit(p)) sum += c[p];return sum;
}int main(){ios::sync_with_stdio(0);cin.tie(0);while(cin >> n){n = n * n; vector <int> c(n + 1,0);int x,ans1,ans2,cnt1,cnt2;cnt1 = cnt2 = ans1 = ans2 = 0;for(int i = 1;i <= n;i++){cin >> x;if(!x) continue;cnt1++;insert(x,1,c);ans1 += cnt1 - query(x,c);}for(int i = 0;i <= n;i++) c[i] = 0;for(int i = 1;i <= n;i++){cin >> x;if(!x) continue;cnt2++; insert(x,1,c);ans2 += cnt2 - query(x,c);}	if(ans1 % 2){if(ans2 % 2) cout << "TAK" << endl;else cout << "NIE" << endl;}else{if(ans2 % 2) cout << "NIE" << endl;else cout << "TAK" << endl;}}return 0;
}

A-star

其实本题不需要可行性判定,但学一下也无妨。

设计估价函数 h ( s t a t e ) h(state) h(state) 表示当前状态所有数字与其目标位置的曼哈顿距离和,即:
h ( s t a t e ) = ∑ i = 1 8 ∣ x i − x t a r g e t ∣ + ∣ y i − y t a r g e t ∣ h(state) = \sum_{i = 1}^{8} \left | x_i - x_{target} \right | + \left | y_i - y_{target} \right | h(state)=i=18xixtarget+yiytarget
显然实际操作数 g ( s t a t e ) ≥ h ( s t a t e ) g(state) \ge h(state) g(state)h(state) ,因为 h h h 表示每个数字去目标点都走最短路,而实际至少得走这么远, h h h 函数可采纳且较接近真实值(相比之下“错位数”,即不在目标位置的数字个数,这一估价函数虽可采纳但大多数时候远小于真实值,求解效率低),最终入队的总代价即为 f = g + h f = g + h f=g+h

代码实现

#include <bits/stdc++.h>using namespace std;const string TARGET = "123804765";
const int dx[] = {0,0,-1,1};
const int dy[] = {-1,1,0,0};struct Node{string state;int g,h,f;Node(string s,int _g,int _h) :state(s),g(_g),h(_h),f(_g + _h) {}//重载运算符bool operator < (const Node& other) const {return f > other.f;} 
};//预处理target状态坐标
void initTargetPos(unordered_map <char,int>& pos_map){for(int i = 0;i < 9;i++){char c = TARGET[i];if(c != '0') pos_map[c] = i;}
} //函数求曼哈顿距离和 
int mahattan(const string& state,const unordered_map <char,int>& pos_map){int distance = 0;for(int i = 0;i < 9;i++){char c = state[i];if(c == '0') continue;int target_pos = pos_map.at(c);//当前数字坐标 int cur_x = i % 3;int cur_y = i / 3;//目标位置坐标 int tar_x = target_pos % 3;int tar_y = target_pos / 3;distance += abs(cur_x - tar_x) + abs(cur_y - tar_y);}return distance;
}int A_star(string start){if(start == TARGET) return 0;//预处理目标位置 unordered_map <char,int> pos_map;initTargetPos(pos_map);priority_queue <Node> open_list;unordered_map <string,int> min_cost;int start_h = mahattan(start,pos_map);open_list.push(Node(start,0,start_h));min_cost[start] = 0;while(!open_list.empty()){Node cur = open_list.top();open_list.pop();string state = cur.state;if(state == TARGET) return cur.g;//非最优路径则跳过if(min_cost[state] < cur.g) continue;//找出0的位置 int pos = state.find('0');int x = pos % 3;int y = pos / 3;for(int i = 0;i < 4;i++){int tx = x + dx[i];int ty = y + dy[i];//越界 if(tx < 0 || tx >= 3 || ty < 0 || ty >= 3) continue;//0的新坐标 int new_pos = tx + ty * 3;string new_state = state;swap(new_state[pos],new_state[new_pos]);int new_g = cur.g + 1;//未曾入队或有更优解 if(min_cost.find(new_state) == min_cost.end() || new_g < min_cost[new_state]){min_cost[new_state] = new_g;int new_h = mahattan(new_state,pos_map);open_list.push(Node(new_state,new_g,new_h));} }}
}int main(){ios::sync_with_stdio(0);cin.tie(0);string start;cin >> start;cout << A_star(start) << endl;return 0;
}

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

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

相关文章

MySQL Buffer Pool 深度解析:从架构设计到性能优化(附详细结构图解)

在 MySQL 数据库的世界里&#xff0c;有一个决定性能上限的"神秘仓库"——Buffer Pool。它就像超市的货架&#xff0c;把最常用的商品&#xff08;数据&#xff09;放在最方便拿取的地方&#xff0c;避免每次都要去仓库&#xff08;磁盘&#xff09;取货。今天我们就…

使用numpy的快速傅里叶变换的一些问题

离散傅里叶变换&#xff08;DFT&#xff09;的频率&#xff08;或波数&#xff09;确实主要由采样点数和物理步长决定。 最高波数和最小波长的乘积是1。单位长度内波的周期数。 &#xff08;注意角波数是 k 2 π λ k \frac{2 \pi}{\lambda} kλ2π​&#xff09; 使用numpy…

DVWA靶场通关笔记-CSRF(High级别)

目录 一、CSRF Token 二、代码审计&#xff08;High级别&#xff09; 1、渗透准备 2、源码分析 三、渗透实战 1、渗透准备 2、修改URL重放失败 3、burpsuite尝试重放失败 4、安装CSRF Token Tracker 5、安装logger插件 6、配置CSRF Token Tracker 7、bp再次重放报文…

Redis实战:数据安全与性能保障

数据安全 持久化策略 RDB持久化&#xff1a;通过创建快照将内存中的数据写入到磁盘上的RDB文件中。可以在配置文件中设置save参数来指定在多少秒内有多少次写操作时触发快照保存。例如&#xff0c;save 900 1表示900秒内至少有1次写操作时保存快照。 AOF持久化&#xff1a;将每…

人脸活体识别3:C/C++实现实时眨眼、张嘴、点头、摇头检测

> 当AI能识破照片与真人的区别,我们才真正跨入生物识别安全时代 --- ### 一、活体检测:数字世界的守门人 **传统人脸识别的致命缺陷**: - 高清照片欺骗成功率 > 85% - 视频回放攻击成本 < $50 - 3D面具破解率高达72% **我们的解决方案**: ```mermaid graph …

【Linux】AlmaLinux 无法使用root用户登录cockpit控制台问题解决

在虚拟机安装AlmaLinux 9.6&#xff0c;安装过程中需要允许使用root用户和SSH协议登录服务器。但是&#xff0c;在使用root用户登录cockpit管理后台时&#xff0c;系统提示“权限被拒绝”。 经过查询资料&#xff0c;可以通过下面的方法来解决此问题。 编辑 /etc/cockpit/disa…

【Java面试】讲讲HashMap的常用方法,以及底层实现?

1. 底层数据结构 数组链表红黑树&#xff08;JDK 1.8&#xff09;&#xff1a; 数组&#xff08;Node[] table&#xff09;存储桶&#xff08;bucket&#xff09;&#xff0c;每个桶是链表或红黑树的头节点。链表解决哈希冲突&#xff0c;当链表长度 ≥ 8 且数组容量 ≥ 64 时…

ToT:思维树:借助大语言模型进行审慎的问题求解

摘要 语言模型正日益被部署于广泛任务中的通用问题求解&#xff0c;但在推理阶段仍受限于 token 级、从左到右的决策过程。这意味着在需要探索、战略前瞻&#xff0c;或初始决策起关键作用的任务中&#xff0c;语言模型可能表现不佳。为克服这些挑战&#xff0c;我们提出了一种…

Web3 + RWA 餐饮数字化解决方案白皮书(试点版)

一、背景&#xff1a;从“用户”到“共创股东”&#xff0c;重构本地生活新逻辑 ✨ 項目愿景&#xff1a; “用一顿饭&#xff0c;链接一个社群&#xff1b;用一次消费&#xff0c;绑定一份权益”。 传统商业以“交易”为中心&#xff0c;未来商业则以“关系 价值流转”为核…

MCU的模拟输入ADC引脚如何实现采样时间与阻抗匹配

在MCU的模拟输入ADC引脚中&#xff0c;实现采样时间与阻抗匹配是关键的设计环节&#xff0c;直接影响采样精度。以下是分步说明&#xff1a; 【】理解信号源阻抗与采样时间的关系 • 信号源阻抗&#xff08;Rs&#xff09;&#xff1a;外部信号源的输出阻抗&#xff08;如传感器…

等价矩阵 线性代数

所谓等价矩阵&#xff0c;就是说其秩相同的矩阵。 例题 A和B等价就是求A和B的秩&#xff0c;其实就是要求B的秩了&#xff0c;因为目标已经告诉你了A和B的秩是一样的。那么怎么求B的秩呢&#xff1f;我们现在只有一种方法求其秩&#xff0c;就是通过把其经过初等变换之后符合标…

30.设计模式的优缺点

原文地址:设计模式的优缺点 更多内容请关注&#xff1a;智想天开 一、设计模式的优点 1. 提高代码复用性与可维护性 复用性&#xff1a; 设计模式提供的是抽象的解决方案&#xff0c;可以在多个项目中重复应用&#xff0c;避免重复造轮子。例如&#xff0c;工厂模式封装了对象…

Python 爬虫实战 | 国家医保

一、国家医保 1、目标网站 网址&#xff1a;https://fuwu.nhsa.gov.cn/nationalHallSt/#/search/drug-directory目标数据&#xff1a;获取药品信息 2、网站特点 服务端返回加密数据&#xff0c;客户端发送请求携带的载荷也是加密的 3、定位解密入口 可以通过关键字encDa…

OpenCV CUDA模块设备层----计算向量的平方根函数sqrt

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 OpenCV 的 CUDA 设备函数&#xff08;device function&#xff09;&#xff0c;用于在 GPU 上计算一个 uchar4 类型向量的平方根&#xff0c;并返…

鸿蒙应用开发:HTTP访问网络

一、HTTP概述 在许多场景下&#xff0c;我们的应用需要从服务端获取数据&#xff0c;例如&#xff0c;天气应用需要从天气服务器获取天气数据。新闻应用需要从新闻服务器获取最新的新闻咨询&#xff0c;通过HTTP数据请求&#xff0c;我们可以将互联网上的信息展示在应用中&…

【Elasticsearch】refresh与提交

在Elasticsearch中&#xff0c;Translog日志的提交确实涉及到与刷新&#xff08;Refresh&#xff09;时写入Lucene段的数据进行合并&#xff0c;并最终写入磁盘。以下是详细的步骤和解释&#xff1a; 一、Translog日志的提交过程 1. 刷新&#xff08;Refresh&#xff09;操作 …

服务器异常宕机或重启导致 RabbitMQ 启动失败问题分析与解决方案

服务器异常宕机或重启导致 RabbitMQ 启动失败问题分析与解决方案 一、深度故障诊断与解决方案1. 权限配置不当故障2. 端口占用故障3. 数据目录残留故障 二、故障类型对比与诊断矩阵三、完整恢复流程&#xff08;10步法&#xff09;四、风险规避与最佳实践&#x1f6e1;️ 数据保…

车载以太网都有什么协议?

目录 一、物理层协议(Physical Layer)二、数据链路层协议(Data Link Layer)三、网络层协议(Network Layer)四、传输层协议(Transport Layer)五、应用层协议(Application Layer)六、车载网络融合协议七、标准化组织八、协议分层总结表九、趋势与未来协议车载以太网涉及…

设计模式之外观模式:简化复杂系统的优雅之道

设计模式之外观模式&#xff1a;简化复杂系统的优雅之道 今天我们来深入探讨设计模式中的外观模式&#xff08;Facade Pattern&#xff09;。想象一下&#xff0c;你走进一家高档餐厅&#xff0c;只需要告诉服务员"我要一份A套餐"&#xff0c;而不需要关心厨房里厨师…

《Python 架构之美:三大设计模式实战指南》

《Python 架构之美:三大设计模式实战指南》 在软件世界中,设计模式是经验的结晶,它为开发者提供了解决重复问题的通用模板。尤其在 Python 这种灵活而强大的语言中,设计模式并非“死规矩”,而更像“编程哲学”,为我们解构复杂系统、提升代码可维护性提供了宝贵思路。 本…