参考了一下紫书的做法,但是具体实现还是有很大不同的,这里给出的代码供参考。
听说很多大佬用的双向广搜?用了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());
}
··