八数码难题

题目传送门

参考了一下紫书的做法,但是具体实现还是有很大不同的,这里给出的代码供参考。

听说很多大佬用的双向广搜?用了IDA*?好像我都不会

我写的就是一个朴素BFS,大佬绕行。

这道题的细节挺多,我也为使用STL付出了一定的码量。(别看完代码就走,后面还有)

C o d e ( C + + 11 ) Code(C++11) Code(C++11)

#include <cstdio>
#include <unordered_set>
#include <queue>
#include <cstring>
#define _for(i, a, b) for (int i = (a); i < (b); i ++)
#define _rep(i, a, b) for (int i = (a); i <= (b); i ++)

using namespace std;

struct State {//状态定义,本来是使用的typedef,但是由于后面使用STL找了半天编译错才试验出来是typedef的锅qwq
	int state[10];//状态数组,state[0~8]表示格子上的数,state[9]表示步数
	inline int operator [] (int x) const {return state[x];};//为了方便重载一下
	inline int& operator [] (int x) {return state[x];}//这里不分两个重载的话会CE
	inline bool operator == (const State x) const {return memcmp(state, x.state, sizeof(state) - 4) == 0;}
	//这里是真的要注意,判断两个状态是否相等要把步数撇开不看,否则就死了。
	//一个整数占4个字节,所以是减4
	inline void operator = (const State x) {memcpy(state, x.state, sizeof(state));}//赋值
};

const int Ans[10] = {1, 2, 3, 8, 0, 4, 7, 6, 5, 0};//目标状态,原题是要输入的,这道题简化了一下目标状态变成常量了,其实也差不多
State st, now, new_;
queue<State> q;
const int movx[] = {-1, 1, 0, 0};//增量数组
const int movy[] = {0, 0, -1, 1};

struct Hash
{
	inline size_t operator () (const State s) const
	{
		int h = 0;
		_rep (i, 0, 8)
		h = (h << 1) + (h << 3) + s[i] - 48;
		return h;
	}
};

unordered_set<State, Hash> s;//这个没学过的可以去参考一下C++11和unordered_set的资料,其实是一个hash表,很方便的

inline int bfs()
{
	q.push(st);
	while (q.size())
	{
		if (memcmp(q.front().state, Ans, sizeof(Ans) - 4) == 0) return q.front()[9];//到达目标状态,返回
		now = q.front()
		q.pop();
		int zero, x, y;//zero表示状态中0的位置
		_rep (i, 0, 8)
		if (now[i] == 0) {zero = i; break;}
		x = zero / 3, y = zero % 3;//计算0所在的行(0~2)和列(0~2)
		_rep (i, 0, 3)
		if (x + movx[i] < 3 && y + movy[i] < 3 && x + movx[i] >= 0 && y + movy[i] >= 0)//向四个方向试探
		{
			new_ = now;
			new_[9] ++;//步数+1
			new_[3 * (x + movx[i]) + y + movy[i]] = 0;交换位置
			new_[zero] = now[3 * (x + movx[i]) + y + movy[i]];
			if (s.count(new_) == 0) s.insert(new_), q.push(new_);//如果该状态没被搜索过,加进表里和队列中
		}
	}
	return 0;//这道题不会无解所以这句话可有可无,强迫症写上去了
}

int main()
{
	_rep (i, 0, 8)
	st[i] = getchar() - 48;
	s.insert(st);
	printf("%d", bfs());
}

update:2020/10/2

本蒟蒻终于学了双向广搜wtcl,于是开个O2卡进了最优解第十……

升 级 版 C o d e : 升级版Code: Code:

#include <cstdio>
#include <unordered_set>
#include <queue>
#include <cstring>
#define _for(i, a, b) for (int i = (a); i < (b); i ++)
#define _rep(i, a, b) for (int i = (a); i <= (b); i ++)

using namespace std;

struct State {
	int state[10];
	inline int operator [] (int x) const {return state[x];};
	inline int& operator [] (int x) {return state[x];}
	inline bool operator == (const State x) const {return memcmp(state, x.state, sizeof(state) - 4) == 0;}
	inline void operator = (const State x) {memcpy(state, x.state, sizeof(state));}
} Ans;

int Array[10] = {1, 2, 3, 8, 0, 4, 7, 6, 5, 0};
State st, now, new_;
queue<State> q, q2;
const int movx[] = {-1, 1, 0, 0};
const int movy[] = {0, 0, -1, 1};

struct Hash
{
	inline size_t operator () (const State s) const
	{
		int h = 0;
		_rep (i, 0, 8)
		h = (h << 1) + (h << 3) + s[i] - 48;
		return h;
	}
};

unordered_set<State, Hash> s, s2;

inline int bfs()
{
	q.push(st); q2.push(Ans);
	while (true)
	{
		now = q.front();
		if (s2.count(now)) return (* s2.find(now)).state[9] + now.state[9];
		q.pop();
		int zero, x, y;
		_rep (i, 0, 8)
		if (now[i] == 0) {zero = i; break;}
		x = zero / 3, y = zero % 3;
		_rep (i, 0, 3)
		if (x + movx[i] < 3 && y + movy[i] < 3 && x + movx[i] >= 0 && y + movy[i] >= 0)
		{
			new_ = now;
			new_[9] ++;
			new_[3 * (x + movx[i]) + y + movy[i]] = 0;
			new_[zero] = now[3 * (x + movx[i]) + y + movy[i]];
			if (s.count(new_) == 0) s.insert(new_), q.push(new_);
		}
		now = q2.front();
		if (s.count(now)) return (* s.find(now)).state[9] + now.state[9];
		q2.pop();
		_rep (i, 0, 8)
		if (now[i] == 0) {zero = i; break;}
		x = zero / 3, y = zero % 3;
		_rep (i, 0, 3)
		if (x + movx[i] < 3 && y + movy[i] < 3 && x + movx[i] >= 0 && y + movy[i] >= 0)
		{
			new_ = now;
			new_[9] ++;
			new_[3 * (x + movx[i]) + y + movy[i]] = 0;
			new_[zero] = now[3 * (x + movx[i]) + y + movy[i]];
			if (s2.count(new_) == 0) s2.insert(new_), q2.push(new_);
		}
	}
}

int main()
{
    memcpy(Ans.state, Array, sizeof(Array));
	_rep (i, 0, 8)
	st[i] = getchar() - 48;
	s.insert(st);
	printf("%d", bfs());
}
··
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值