P1379 八数码难题

2 篇文章 0 订阅
2 篇文章 0 订阅

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:
283104765
输出样例#1:
4








用这道题复习了下bfs以及hash

显然这题求最小步数应当要用bfs

此处直接存了八数码的九个位置的数(当然也可以转为一个九位数,在九位数上进行操作)

然后把八数码转换为一个九位数,用hash来判重。(九位数太大,开一个10^10的数组浪费太多空间并且也开不下,而所有可能情况只有 9! 种)

第一次写没有注意到了边界

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue> 
using namespace std;
typedef long long LL;
const int hn = 199999; 
const int fx[4] = {1,-1,0,0};
const int fy[4] = {0,0,1,-1};
struct data{
	int a[3][3],n;
	data(int n = 1){
		memset(a,0,sizeof(a));
	}
	bool operator == (const data &b){
		for(int i = 0; i < 3; i++){
			for(int j = 0; j < 3; j++){
				if(a[i][j] != b.a[i][j]) return false;
			}
		}
		return true;
	}
};
data s,e;
int N;
queue<data> q;
vector<LL> h[hn]; 
inline int get(){
	char c;
	while((c = getchar()) < '0' || c > '9');
	int cnt = c - '0';
	while((c = getchar()) >= '0' && c <= '9') cnt = cnt * 10 + c - '0';
	return cnt;
}
inline LL cal(data a){
	LL ans = 0;
	for(int i = 0; i < 3; i++){
		for(int j = 0; j < 3; j++){
			ans = ans * 10 + a.a[i][j];
		}
	}
	return ans;
}
inline void hs(LL a){
	int k;
	k = a % hn;
	h[k].push_back(a);
	return;
}
inline bool judge(LL a){
	int k;
	k = a % hn;
	for(int i = 0; i < h[k].size(); i++){
		if(h[k][i] == a) return true;
	}
	return false;
}
int main(){
	#ifdef lwy
/*	#else
		freopen(".in","r",stdin);
		freopen(".out","w",stdout);*/
	#endif
	e.a[0][0] = 1; e.a[0][1] = 2; e.a[0][2] = 3;
	e.a[1][0] = 8; e.a[1][1] = 0; e.a[1][2] = 4;
	e.a[2][0] = 7; e.a[2][1] = 6; e.a[2][2] = 5;
	N = get();
	for(int i = 2; i >= 0; i--){
		for(int j = 2; j >= 0; j--){			
			s.a[i][j] = N % 10;
			N /= 10;
		}
	}
	q.push(s);
	hs(cal(s));
	while(!q.empty()){
		data f = q.front(); q.pop();
		int px,py;
		for(int i = 0; i < 3; i++){
			for(int j = 0; j < 3; j++){
				if(f.a[i][j] == 0){
					px = i; py = j;
					break;
				}
			}
		}
		for(int i = 0; i < 4; i++){
			int tx = px + fx[i]; int ty = py + fy[i];
			if(tx < 0 || tx > 2 || ty < 0 || ty > 2) continue; //
			data d = f; int p;
			d.n = f.n + 1;
			p = d.a[px][py];
			d.a[px][py] = d.a[tx][ty];
			d.a[tx][ty] = p;
			if(d == e){
				printf("%d",d.n);
				return 0;
			}
			if(!judge(cal(d))){
				q.push(d);
				hs(cal(d));
			}
		}
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值