题目大意:
给一个3*3的矩阵,通过‘x’(可以看成空格)移动,使得最后的矩阵形式为标准型。
解题思路:
自己一脸懵逼,从网上找了其他人的思路,大概看懂了。
9!=362880,所以定义一个F数组,记录当前状态属于第几种状态。
dxdy数组第i为可以移动到几号位,qs记录开始序列,qe记录结束序列。
这里我们介绍一种可以将全排列的一种表示为“第几个排列”的方法——康托展开。
首先看几个康托展开的实例(9的全排列):
1 2 3 4 5 6 7 8 9——展开为 0。
1 2 3 4 5 6 7 9 8——展开为 1。
1 2 3 4 5 6 8 7 9——展开为 2。
由这些最开始的方法我们可以发现一个规律:从第一个数开始,依次判断判断这些数是当前没有出现过的数的第几个(由0开始),记为a1, a2, … ,a(n - 1)。不难发现如1 2 3 4 5 6 8 7 9,由1至6都是当前没有出现过的第0个数,而8是7,8,9中的第1个(由0开始),9是7,9中的第1个,7是第0个。故a1 = a2 = … = a6 = 0,a7 = 1,a8 = 1,a9 = 0。
之后排列数(康托展开的值)等于
a1 * (n - 1)! + a2 * (n - 2)! + … + ak * (n - k)! + … + an * 0!
再举几个例子:
3 5 7 4 1 2 9 6 8——展开为 98884。
5 6 7 8 1 2 3 4 9——展开为 184800。
至于双向BFS 就是知道初始和目标状态的情况下,就可以正向反向一起广搜,找到一个另一方向已搜到过的节点就得到解了
一般来讲每次选择队列中节点比较少的一边来进行下一次搜索。
双向BFS的代码
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const string des="123456780";
int F[362881];
int fact[9]={1,1,2,6,24,120
,720,5040,40320};
string beg="123456780";
int xpos;
int dxdy[10][4]=
{
{-1,-1,1,3},
{-1,0,2,4},
{-1,1,-1,5},
{0,-1,4,6},
{1,3,5,7},
{2,4,-1,8},
{3,-1,7,-1},
{4,6,8,-1},
{5,7,-1,-1}
};
char dir[4]={'u','l','r','d'};
struct node
{
string cur;
string op;
int pos;
}qs[362881],qe[362881];
long hashfun(const string&s)
{
long r=0;
for(int i=1;i<9;i++)
{
int num=0;
if(i<5)
{
for(int j=0;j<i;j++)
{
if(s[j]>s[i])
++num;
}
}
else
{
for(int j=i+1;j<9;j++)
{
if(s[j]>s[i])
++num;
}
num=8-(s[i]-'0')-num;
}
r+=num*fact[i];
}
return r;
};
string BFS()
{
int head1,head2,rear1,rear2;
head1=head2=0;
rear1=rear2=1;
qs[0].cur=beg;
qs[0].op = "";
qs[0].pos=xpos;
F[hashfun(beg)]=1;
qe[0].cur=des;
qe[0].op="";
qe[0].pos=8;
F[hashfun(des)]=2;
while(rear1+rear2<181441)
{
if(rear1-head1<rear2-head2)
{
if(head1<rear1)
{
node temp=qs[head1];
++head1;
int pos=temp.pos;
for(int i=0;i<4;i++)
{
if(dxdy[pos][i]<0)
continue;
int cpos=dxdy[pos][i];
string ts=temp.cur;
ts[pos]=ts[cpos];
ts[cpos]='0';
long hv=hashfun(ts);
string cop=temp.op+dir[i];
if(F[hv]%10==2)
return cop+qe[F[hv]/10].op;
else if(F[hv]==0)
{
F[hv]=rear1*10+1;
qs[rear1].cur=ts;
qs[rear1].op=cop;
qs[rear1++].pos=cpos;
}
}
}
}
else
{
if(head2<rear2)
{
node temp=qe[head2];
++head2;
int pos=temp.pos;
for(int i=0;i<4;i++)
{
if(dxdy[pos][i]<0)
continue;
int cpos=dxdy[pos][i];
string ts=temp.cur;
ts[pos]=ts[cpos];
ts[cpos]='0';
long hv=hashfun(ts);
string cop=dir[3-i]+temp.op;
if(F[hv]%10==1)
{
return qs[F[hv]/10].op+cop;
}
else if(F[hv]==0)
{
F[hv]=rear2*10+2;
qe[rear2].cur=ts;
qe[rear2].op=cop;
qe[rear2++].pos=cpos;
}
}
}
}
}
};
int count(const string&s)
{
int ct=0;
for(int i=1;i<9;i++)
{
if(s[i]=='0')
continue;
for(int j=0;j<i;j++)
{
if(s[j]>s[i])
ct++;
}
}
return ct;
};
int main()
{
while(cin>>beg[0])
{
cin>>beg[1]>>beg[2]>>beg[3]>>beg[4]
>>beg[5]>>beg[6]>>beg[7]>>beg[8];
for(xpos=0;xpos<9;++xpos)
{
if(beg[xpos]=='x')
{
beg[xpos]='0';
break;
}
}
memset(F,0,sizeof(F));
if(count(beg)&1)
printf("unsolvable\n");
else
{
string s=BFS();
int len=s.length();
for(int i=0;i<len;i++)
printf("%c",s[i]);
printf("\n");
}
}
return 0;
}