题意:八数码。
思路:将上一篇博客的估计函数h更改为求当前状态到目标状态的曼哈顿距离,因为每次都是和空格交换,所以计算的时候不计算空格的曼哈顿距离就可以满足估计函数的两条性质:
1.h(n)>h'(n),h'(n)为从当前节点到目标点的实际的最优代价值。
2.每次扩展的节点的f值大于等于父节点的f值小。
对于这道题的样例而言,两个估计函数效率差不多,简化版的优化函数(只计算两个状态相同位置不同值的数量)甚至还要比曼哈顿的优化函数要好一些。
(上面的是曼哈顿距离做优化函数的实现,下面是简化版估计函数的实现)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 400000;
//const int INF = 0x3f3f3f3f;
bool has[MAXN];
int fac[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};
int last[MAXN];
short int mov[MAXN];
struct State {
int f, g;
int s[9];
int pos;
int hash;
bool operator < (const State& A) const {
return A.f==f ? g>A.g : f>A.f;
}
} ini, target;
int cal_h(int* s1) {
int ans = 0;
for(int i = 0; i < 9; i++) {
if(s1[i] == 9) continue;
int x = (s1[i]-1)/3, y = (s1[i]-1)%3;
int nx = i/3, ny = i%3;
ans += abs(x-nx) + abs(y-ny);
}
return ans;
}
priority_queue<State> q;
int Hash(int* s) {
int res = 0;
for(int i = 0; i < 8; i++) {
int cnt = 0;
for(int j = i + 1; j < 9; j++) {
if(s[i] > s[j]) cnt++;
}
res += cnt * fac[8-i];
}
return res;
}
int cal_pos(int pos, int i) {
int nx = pos/3+dx[i], ny = pos%3+dy[i];
if(nx<0 || nx>2 || ny<0 || ny>2) return -1;
return nx*3 + ny;
}
void BFS() {
for(int i = 0; i < 9; i++) target.s[i] = i+1;
target.pos = 8;
target.hash = 0;
has[0] = 1;
q.push(target);
while(!q.empty()) {
State ha = q.top();
q.pop();
State tmp;
for(int i = 0; i < 4; i++) {
tmp.pos = cal_pos(ha.pos, i);
tmp.g = ha.g + 1;
if(tmp.pos<0) continue;
for(int j = 0; j < 9; j++) {
if(j==ha.pos) tmp.s[j] = ha.s[tmp.pos];
else if(j == tmp.pos) tmp.s[j] = ha.s[ha.pos];
else tmp.s[j] = ha.s[j];
}
tmp.hash = Hash(tmp.s);
if(has[tmp.hash]) continue;
tmp.f = ha.f + cal_h(tmp.s);
q.push(tmp);
has[tmp.hash] = 1;
last[tmp.hash] = ha.hash;
mov[tmp.hash] = i;
}
}
}
void print_path(int x) {
if(x==0) return;
int i = mov[x];
if(!i) printf("d");
else if(i==1) printf("r");
else if(i==2) printf("u");
else printf("l");
print_path(last[x]);
}
int main() {
//freopen("input.txt", "r", stdin);
memset(has, 0, sizeof(has));
BFS();
char tmp;
while(cin >> tmp) {
if(tmp != 'x') ini.s[0] = tmp - '0';
else {
ini.s[0] = 9;
ini.pos = 0;
}
for(int i = 1; i < 9; i++) {
cin >> tmp;
if(tmp == 'x') {
ini.s[i] = 9;
ini.pos = i;
}
else ini.s[i] = tmp - '0';
}
ini.hash = Hash(ini.s);
if(!has[ini.hash]) printf("unsolvable");
else print_path(ini.hash);
puts("");
}
return 0;
}