八数码问题(bfs)

 方式一:string存储状态

题目传送门:845. 八数码 - AcWing题库

BFS适用于边权为1的最短路问题 ,而这题要求最少的交换次数,将每一次的九宫格状态当作一个“状态结点”,由当前这个结点可以扩展出其它状态【即 x 可以与其上下左右(若存在的话)交换】,每一种可能的交换都将是bfs“踏出的下一步结点”。

这题难在如何存储状态,并且同一种状态将会有多种方式得出,需要 “ 去重 ” 保存状态,每一个状态对应到达该状态的最短路(即x的交换次数)是多少,于是我们想到用map来存【状态-步数】,同样bfs队列里也加入到达的状态,九宫格的状态可以用字符串来表示。

编码阶段:九宫格转换为字符串存储

解码阶段:字符串转换为九宫格后  ,再加以交换操作

编码和解码的转换通过stirng的下标 与 九宫格的横纵坐标的联系来实现:设字符 x 在string中的下标为t,则在九宫格a中为 a[t/3][t%3] 。(下标都从0开始)同样地,九宫格中某个数字的横纵坐标分别为x和y,则其在sting中存储的下标应为 x*3+y。

本题还学到了swap交换的对象之广泛,可以直接对string中的两个字符做交换。

(此外unordered_map在此题中比普通map要快)

 上代码:

#include<iostream>
#include<queue>
#include<string>
#include<unordered_map>
using namespace std;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};    //下标偏移数组,分别对应x的上右下左
unordered_map<string,int> mp;
queue<string> q;
int bfs(){
	string s;
	while(!q.empty()){
		s=q.front();
		q.pop();
		int stp=mp[s];
		if(s=="12345678x")return stp;
		int t=s.find('x');  //寻找下标
		int x=t/3, y=t%3;   //由下标得到横纵坐标
		for(int i=0,tx,ty;i<4;i++){
			tx=x+dx[i];
			ty=y+dy[i];
			if(tx<0||tx>=3||ty<0||ty>=3)continue;//注意此处是>=3不是>3
			int t2=tx*3+ty;     //转换为横纵坐标
			swap(s[t],s[t2]);
			if(!mp.count(s)){   //判重
				mp[s]=stp+1;
				q.push(s);
			}
			swap(s[t],s[t2]);
		}
	}
	return -1;
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	string s,t;
	for(int i=0;i<9;i++){
		cin>>t;
		s+=t;
	}
	q.push(s);
	mp[s]=0;
	cout<<bfs();
	return 0;
}

 

 方式二:用一个数(long long)存储状态

当然,这个适合输入全是数的情况(如x换为0)

题目传送门:P1379 八数码难题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

 犯过的错就是,注意横纵坐标对应,从0开始存的就横纵坐标<3,从1开始存的就<=3 QAQ

直接上代码:

#include<iostream>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
map<ll,int> mp;
queue<ll> q;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1},a[5][5];
ll t;
int bfs(){
	while(!q.empty()){
		t=q.front();
		q.pop();
		int stp=mp[t], x, y;
		if(t==123804765)return stp;
		//数转矩阵 
		for(int i=3;i>0;i--){
			for(int j=3;j>0;j--){
				a[i][j]=t%10;
				t/=10;
				if(!a[i][j])x=i, y=j;
			}
		}
		for(int i=0,tx,ty;i<4;i++){
			tx=x+dx[i];
			ty=y+dy[i];
			if(tx<1||tx>3||ty<1||ty>3)continue;
			swap(a[x][y],a[tx][ty]);
			//矩阵转数
			t=0;
			for(int i=1;i<=3;i++){
				for(int j=1;j<=3;j++){
					t=t*10+a[i][j];
				}
			} 
			if(!mp.count(t)){
				mp[t]=stp+1;
				q.push(t);
			}
			swap(a[x][y],a[tx][ty]);
		}
	}
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);//可忽略,关同步流来提速的
	cin>>t;
	q.push(t);
	mp[t]=0;
	cout<<bfs();
	return 0;
}

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
八数码问题的解决方法中,C语言可以使用BFS(广度优先搜索)算法来解决。在C语言中,可以通过实现一个EightDigital类来解决八数码问题。通过BFS算法可以找到从初始状态到目标状态的最短路径。在该算法中,通过队列的方式,一层一层地扩展状态空间,直到找到目标状态。 在该实现中,可以使用一个辅助数组来记录每个状态的前驱状态,以便打印出从初始状态到目标状态的路径。具体实现中,可以使用一个stack来存储路径,从目标状态开始,通过查找前驱状态一直到初始状态,将每个状态压入栈中,最后依次弹出栈顶元素即可得到路径。同时,使用一个变量记录步数,即栈的大小,即可得到解的步数。 除了BFS算法外,还可以使用A*算法来解决八数码问题。A*算法是一种启发式搜索算法,通过评估函数来估计从当前状态到目标状态的代价,并选择代价最小的状态进行扩展。在八数码问题中,可以使用曼哈顿距离作为评估函数,即当前状态到目标状态的每个数字所需的水平和垂直移动的总和。通过A*算法可以更快地找到最优解。 总结起来,八数码问题可以使用C语言中的BFS算法和A*算法来解决。BFS算法可以找到最短路径,A*算法可以更快地找到最优解。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [c++八数码难题全家桶(A*算法、双向BFSBFS、DFS)](https://blog.csdn.net/qq_54893805/article/details/127440809)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值