参考了一下紫书的做法,但是具体实现还是有很大不同的,这里给出的代码供参考。
听说很多大佬用的双向广搜?用了IDA*?好像我都不会。
我写的就是一个朴素BFS,大佬绕行。
这道题的细节挺多,我也为使用STL付出了一定的码量。
:
#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~9]表示格子上的数,state[10]表示步数
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};
int dis[1000005];
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());
}