版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84378680
思路分析:
考虑将8数码的每个格局对应一个9位的9进制数(long long类型), 如果直接使用BFS或DFS的一个直接结果是超时. 因此使用A*, 估价函数为从当前状态(格局)s和目标状态t相等元素的曼哈顿距离之和, 易证该估价函数满足要求. 下面给出基于此策略的AC代码:
//POJ1077_Eight
#include <iostream>
#include <functional>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#define mp make_pair
#define fi first
#define se second
using namespace std;
struct state; typedef long long ll; typedef pair<int, int> pii; typedef pair<pii, ll> piill;
const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
const char dir[4] = {'u', 'd', 'l', 'r'};
map<int ,pii> vis;//vis[i].first:状态i对应的最少变换次数, second: 最后一次变换的操作
priority_queue<piill, vector<piill>, greater<piill> > pq;
struct state{
int sta[4][4]; pii pos[10];//pos[i]:数字i在sta中位置
bool operator == (const state &a){
for(int i = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j) if(sta[i][j] != a.sta[i][j]) return false;
return true;
}
//返回本状态对象对应的9进制数
ll getNum(){
ll res = 0;
for(int i = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j) res = res * 9 + sta[i][j];
return res;
}
//从num还原本对象
void re(ll num){
for(int i = 3; i >= 1; --i)
for(int j = 3; j >= 1; --j)
sta[i][j] = num % 9, pos[num % 9].fi = i, pos[num % 9].se = j, num /= 9;
}
//返回当前状态到目标状态T的交换次数下限
int getCnt(const state &T){
int res = 0;
for(int i = 0; i <= 8; ++i)
res += abs(pos[i].fi - T.pos[i].fi) + abs(pos[i].se - T.pos[i].se);
return res;
}
//交换state[a][b]和state[c][d]
void Swap(int a, int b, int c, int d){
swap(pos[sta[a][b]], pos[sta[c][d]]), swap(sta[a][b], sta[c][d]);
}
};
state beg, tar;//初始状态, 目标状态
int main(){
//初始化tar
for(int i = 1, k = 0; i <= 3; ++i)
for(int j = 1; j <= 3; ++j) tar.sta[i][j] = ++k, tar.pos[k].fi = i, tar.pos[k].se = j;
tar.sta[3][3] = 0, tar.pos[0].fi = 3, tar.pos[0].se = 3;
//初始化beg
for(int i = 1, t; i <= 3; ++i)
for(int j = 1; j <= 3; ++j){
char ch; cin >> ch;
if(ch == 'x') beg.sta[i][j] = 0, beg.pos[0].fi = i, beg.pos[0].se = j;
else t = ch - '0', beg.sta[i][j] = t, beg.pos[t].fi = i, beg.pos[t].se = j;
}
ll bn = beg.getNum(), tn = tar.getNum();
pq.push(mp(mp(beg.getCnt(tar), 0), bn)), vis[bn] = mp(0, -1);
while(!pq.empty()){
int val = pq.top().fi.se; ll tnum = pq.top().se; pq.pop(); state s; s.re(tnum);
if(tnum == tn) break;
int x = s.pos[0].fi, y = s.pos[0].se;
for(int i = 0, u, v; i <= 3; ++i)
if(u = x + dx[i], v = y + dy[i], u >= 1 && u <= 3 && v >= 1 && v <= 3){
state stmp = s; stmp.Swap(x, y, u, v); int z = stmp.getNum();
if(vis.count(z)) continue;
pq.push(mp(mp(val + 1 + stmp.getCnt(tar), val + 1), z))
, vis[z] = mp(val + 1, i);
}
}
if(!vis.count(tn)) cout << "unsolvable" << endl;
else{
//还原出解决方案
vector<int> vec; ll k = tn;
while(k != bn){
int y = vis[k].se;
vec.push_back(y); state s; s.re(k);
s.Swap(s.pos[0].fi, s.pos[0].se, s.pos[0].fi - dx[y], s.pos[0].se - dy[y]);
k = s.getNum();
}
for(int i = vec.size() - 1; i >= 0; --i) cout << dir[vec[i]]; cout << endl;
}
}