【启发式搜索】八数码问题
首先就是f(n)=g(n)+h(n)这个h(n)就是估价函数,然后每次更新一下g(n)然后用康托展开,搞一下判重就好了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int MAXVIS = 1000000;
struct State{
int s[9];
int step;
int h, g;
bool operator < (const State& s) const {
return (g+h)>(s.g+s.h);
}
bool operator > (const State& s) const {
return (g+h)<(s.g+s.h);
}
}st, ed;
priority_queue<State> que;
int _pow[9]; pair<int, int> show[9];
int fx[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
bool vis[MAXVIS+5];
int hash(int s[]){
int ret = 0, count =0 ;
for(int i=0;i<9;i++){
count = 0;
for(int j=i+1;j<9;j++)
count += int(s[j]<s[i]);
ret += count * _pow[8-i];
}
return ret;
}
int _abs(int u){return u>0?u:-u;}
int _h(int s[]){
int ret = 0;
for(int i=0;i<9;i++) if(s[i])
ret += _abs(i/3-show[s[i]].first) + _abs(i%3-show[s[i]].second);
return ret;
}
bool check(State s){
for(int i=0;i<9;i++)
if(s.s[i] != ed.s[i])
return false;
return true;
}
bool check_pos(int a, int b){
if(a > 2 || b > 2 || a < 0 || b < 0)
return false;
return true;
}
void solve(){
//printf("666");
State tmp=st; State t2;
int id=hash(st.s);
vis[id] = true;
tmp.h = _h(st.s); tmp.h = 0;
que.push(tmp);
while(!que.empty()){
//printf("6");
tmp = que.top(); que.pop();
//printf("6");
if(check(tmp)) break;
int zx=0, zy=0, pos=0;
while(tmp.s[pos]) pos++;
zx = pos / 3; zy = pos % 3;
for(int i=0;i<4;i++) {
int nzx = zx + fx[i][0], nzy = zy + fx[i][1];
//printf("6");
if(check_pos(nzx, nzy)){
t2 = tmp;
swap(t2.s[pos], t2.s[nzx*3+nzy]);
id = hash(t2.s);
if(vis[id]) continue;
vis[id] = true;
t2.g++; t2.step++;
t2.h = _h(t2.s);
que.push(t2);
}
}
}
if(check(tmp)) printf("%d\n", tmp.step);
else printf("-1\n");
}
int main(){
_pow[0] = 1;
for(int i=1;i<=8;i++) _pow[i] = _pow[i-1] * i;
for(int i=0;i<9;i++) scanf("%d", &st.s[i]);
for(int i=0;i<9;i++){
scanf("%d", &ed.s[i]);
show[ed.s[i]] = make_pair(i/3, i%3);
}
if(check(st)) printf("0\n");
else solve();
return 0;
}