//这道题有收藏题解!
//加上一个估计距离来减少搜索的范围
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<unordered_map>
#define x first
#define y second
using namespace std;
//因为要小根堆排序,所以距离int放第一位
typedef pair<int, string> PIS;
//估计函数,估计当前状态的每个数到终点状态的距离和,这道题中采用了曼哈顿距离
int f(string m)
{
int dis=0;
for(int i=0; i<9; i++)
{
if(m[i] != 'x')
{
int t=m[i]-'1';//找出来这个数是谁
//计算它到原本位置的距离
dis=dis+abs(i/3-t/3)+abs(i%3-t%3);
}
}
return dis;
}
string bfs(string start)
{
string end="12345678x";//终点
unordered_map<string, int> d;//存储每个状态到起点的距离
priority_queue<PIS, vector<PIS>, greater<PIS> > heap;//小根堆,代替队列,将元素的估计终点距离从小到大排列
unordered_map<string, pair<string, char> > last;//存一个元素string,由哪一个状态通过何种操作char转移而来
//以前bfs扩展是瞎扩展的,现在是按照一个预估距离最近的扩展的
heap.push({f(start), start});//加入起点
d[start]=0;//起点到起点的距离为0
//要将操作数组与坐标变化数组一一对应
char oper[]="udlr";
int dx[]={-1, 1, 0, 0}, dy[4]={0, 0, -1, 1};
while(heap.size())
{
auto t=heap.top();
heap.pop();
string state=t.y;//记录状态
if(state == end) break;
int x, y;//查找空格所在位置的横纵坐标
for(int i=0; i<9; i++)
{
if(state[i]=='x')
{
x=i/3, y=i%3;
break;
}
}
//找到以后进行四个方向的扩展
string init=state;//有四次修改,需要记录原始状态
for(int i=0; i<4; i++)
{
int a=x+dx[i], b=y+dy[i];
if(a<0 || a>=3 ||b<0 || b>=3) continue;//越界则跳过
//交换
swap(state[a*3+b], state[x*3+y]);
//如果交换后的新的状态没有被记录过,或者小于原来的值
if(!d.count(state) || d[state]>d[init]+1)
{
d[state]=d[init]+1;
heap.push({f(state)+d[state], state});//加入堆中,距离是到起点的距离+到终点的预估距离
//标记由哪种状态转移而来和对应的操作
last[state]={init, oper[i]};
}
state=init;//因为要扩展四个方向,所以要还原
}
}
//输出操作的路径
string ans;
while(end!=start)
{
ans+=last[end].y;
end=last[end].x;
}
reverse(ans.begin(), ans.end());//反转
return ans;
}
int main()
{
string start, x, c;
while(cin>>c)//这样可以忽略空格
{
start+=c;
if(c!="x") x+=c;
}
int res=0;//统计逆序对的数量
for(int i=0; i<8; i++)
for(int j=i+1; j<8; j++)
if(x[i]>x[j])
res++;
if(res%2) printf("unsolvable\n");//如果逆序对为奇数,就不可能抵达终点,有证明,在收藏的题解里
else cout<<bfs(start)<<endl;
return 0;
}