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
的优先队列优先选择:已走步数+目标预估距离,有方向。最最少的路,而且直奔方向。

相关推荐
Yungoal2 小时前
C++基础项目结构
数据结构·c++·算法
扶摇接北海1762 小时前
洛谷:B4477 [语言月赛 202601] 考场安排
数据结构·c++·算法
爱丽_2 小时前
AQS 的 `state`:volatile + CAS 如何撑起原子性与可见性
java·前端·算法
2301_788770552 小时前
OJ模拟5
数据结构·算法
羊小猪~~2 小时前
算法/力扣--字符串经典题目
c++·考研·算法·leetcode·职场和发展·哈希算法
攒了一袋星辰2 小时前
10万级用户数据日更与定向推送系统的可靠性设计
java·数据库·算法
nap-joker2 小时前
PIPE4:快速PPI预测器,用于综合的跨物种和跨物种相互作用组
算法·多模态生物医学数据分析·蛋白质互作网络
磊 子2 小时前
类和对象—>析构+拷贝+运算符重载
开发语言·c++·算法
人道领域2 小时前
LeetCode【刷题日记】:数组篇(1)含原理讲解
算法·leetcode·职场和发展