A*算法——# P1379 八数码难题

P1379 八数码难题

题目描述

在 3 × 3 3\times 3 3×3 的棋盘上,摆有八个棋子,每个棋子上标有 1 1 1 至 8 8 8 的某一数字。棋盘中留有一个空格,空格用 0 0 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为 123804765 123804765 123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入格式

输入初始状态,一行九个数字,空格用 0 0 0 表示。

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数。保证测试数据中无特殊无法到达目标状态数据。

输入输出样例 #1

输入 #1

复制代码
283104765

输出 #1

复制代码
4

说明/提示

样例解释

图中展示了样例当中从初始状态到目标状态的一种方案,共需要 4 4 4 步。

并且可以证明,不存在更优的策略。

代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
struct coor{int x,y;};//点的坐标 
struct node{
	string ss,//起始布局 
			se="123804765"; //目标布局 
	coor poss[9],//起始布局,各数字的位置 
		 pose[9];//目标布局 
	int id,//哈希值,用于标记 
		dis,//当下布局到目标布局的曼哈顿距离,纵横差 
		step,//当前已经移动的步数 
		x,y;//当前布局0(空格)所在坐标 
	node(){
		step=0;
		se="123804765";
		for(int i=0;i<9;i++)pose[se[i]-'0'].x=i/3,pose[se[i]-'0'].y=i%3;//计算目标布局各数字坐标 
	}
	void set(string s){//初始化,赋予初始布局 
		ss=s;
		for(int i=0;i<9;i++){
			poss[ss[i]-'0'].x=i/3,poss[ss[i]-'0'].y=i%3;//明确起始布局各数字坐标 
			if(ss[i]=='0')x=i/3,y=i%3;//0(空格)所在坐标 
		}
		m_id();m_dis();//计算哈希值和曼哈顿距离和
	}
	void move(int sx,int sy,int ex,int ey){//当前数字移到空格位置 
		poss[ss[sx*3+sy]-'0'].x=ex,poss[ss[sx*3+sy]-'0'].y=ey,//当前数字的坐标变成空格的坐标 
		poss[0].x=sx,poss[0].y=sy,//空格移到对应数字位置 
		swap(ss[sx*3+sy],ss[ex*3+ey]);//对调字符串中0和当前数字的位置 
		x=sx,y=sy;//空格的新位置 
		m_id();m_dis();// 
		step++;
	}
	void m_id(){//计算哈希值,字符串转整数 
		id=0;
		for(int i=0;i<9;i++)id=id*10+ss[i]-'0';
	}
	void m_dis(){//计算各数字到目标布局的曼哈顿距离和 
		dis=0;
		for(int i=0;i<9;i++)dis+=abs(poss[i].x-pose[i].x)+abs(poss[i].y-pose[i].y);
	}
	bool operator<(const node b)const{return step+dis>b.step+b.dis;}//大顶堆默认<,现需要逆序,所以相反成> 
	//a*算法的核心,相对于宽搜、dijstra算法的区别
	//宽搜没有优先队列,
	//dijkstra的优先队列只看已走了多少 
}sta1,sta2;//移动前后布局 
string s;
priority_queue<node> q;//优先队列,默认大顶堆,现在是逆序小顶堆,每次找最小成本状态 
unordered_set<int> vis;//用哈希值记住已遍历布局 
int sx,sy,ex,ey,
	d[4][2]={{0,-1},{-1,0},{0,1},{1,0}};
int main(){
	//freopen("data.cpp","r",stdin);
	cin>>s;
	sta1.set(s);
	q.push(sta1);vis.insert(sta1.id);
	while(!q.empty()){
		sta1=q.top();q.pop();
		if(sta1.dis==0){cout<<sta1.step;return 0;}
		sx=sta1.x,sy=sta1.y;
		for(int i=0;i<4;i++){
			ex=sx+d[i][0],ey=sy+d[i][1];
			if(ex<0||ex>2||ey<0||ey>2)continue;
			sta2=sta1;
			sta2.move(ex,ey,sx,sy);
			if(vis.count(sta2.id))continue;
			vis.insert(sta2.id);
			q.push(sta2);
		}
	}
	cout<<-1;
	return 0;
}

搜索算法横向比较

1968 年,Hart、Nilsson、Raphael 三个人提出了a算法,叫一类带启发式的最佳优先搜索算法。叫Algorithm A→ 就是「A 类算法」,3星4星启发式搜索算法。
几种搜索都是宽搜DFS,标记遍历,访问队列,一直扩散搜索范围。走到哪算哪!
Dijkstra是用了优先队列,优先选择已走步数最少的,如果节点权值一样就退化成DFS。走最少的路,但管不了方向。
A
的优先队列优先选择:已走步数+目标预估距离,有方向。最最少的路,而且直奔方向。

相关推荐
灯澜忆梦2 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下2 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J2 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛2 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有3 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode
aqiu1111113 小时前
【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
c++·算法·leetcode
黄金龙PLUS3 小时前
如何基于置换算法来设计对称加密算法
算法·网络安全·密码学·哈希算法·同态加密
不会就选b3 小时前
算法日常・每日刷题--<动态规划>14
算法
赛博守夜人3 小时前
跨境业务与出海合规之九:海外买量投放与营销虚假流量(Ad Fraud):跨国机房群控与归因欺诈识别算法
算法·安全
镜子AI6 小时前
教培机构AI推荐系统实战:概念漂移检测算法——为什么“去年有效的推荐今年可能失效“
人工智能·算法