瞻仰下八数码,可惜效率还不行啊,看到那么多0MS的,打击啊。。。这题如果要0MS,必须是A*吧,呵呵 可惜还不会呀。。。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
int dir;
int pre;
int step;
char x[10];
}l[400000];
char x[15];
char ansx[15]="123456780";
int perm[] = {1,1,2,6,24,120,720,5040,40320};//n!
int d[] = {-1,-3, 1, 3};//四个方向的下标变换,左上右下。
bool move[][4] = {0,0,1,1, 1,0,1,1, 1,0,0,1, 0,1,1,1, 1,1,1,1, 1,1,0,1, 0,1,1,0, 1,1,1,0, 1,1,0,0};
//各个位置的可行变换
int v[362881];//数组判重
int hash()//用逆序数和变进制进行hash
{
int h = 0;
for(int i = 1;i<9;i++)
{
int count = 0;
for(int j=0;j<i;j++)
if(x[j] > x[i])count ++;
h += count * perm[i];
}
return h;
}
void input()
{
char t[5];
for(int i=0;i<9;i++)
{
scanf("%s",t);
x[i]=t[0];
if(x[i]=='x')
x[i]='0';
}
}
int pos;
void search(char x[])
{
for(int i=0;i<9;i++)
if(x[i]=='0')
{
pos=i;
break;
}
}
char ans[4000000]={0};
void GetDir(int h)
{
memset(ans,0,sizeof(ans));
int i;
int n=l[h].step;
for(i=n;i>=1;i--)
{
if(l[h].dir==0)
ans[i]='l';
else if(l[h].dir==1)
ans[i]='u';
else if(l[h].dir==2)
ans[i]='r';
else if(l[h].dir==3)
ans[i]='d';
h=l[h].pre;
}
}
int main()
{
int head,tail;
memset(v,0,sizeof(int)*362881);
head=tail=1;
input();
//
int code=hash();
v[code]=1;
l[head].step=0;
l[head].pre=-1;
strcpy(l[head].x,x);
//initial
while(head<=tail)
{
if(strcmp(l[head].x,ansx)==0)
break;//此时head为所求解
search(l[head].x);
for(int i=0;i<4;i++)
{
if(move[pos][i]==0)
continue;
strcpy(x,l[head].x);
int np=pos+d[i];
swap(x[pos],x[np]);
int code=hash();
if(!v[code])
{
tail++;
v[code]=1;
l[tail].step=l[head].step+1;
l[tail].pre=head;
l[tail].dir=i;
strcpy(l[tail].x,x);
}
}
head++;
}
if(head>tail)
printf("unsolvable\n");
else
{
GetDir(head);
printf("%s\n",ans+1);
}
return 0;
}
另外那个十五数码,能用程序搞出来么?
这里的哈希函数是用能对许多全排列问题适用的方法。取n!为基数,状态第n位的逆序值为哈希值第n位数。对于空格,取其(9-位置)再乘以8!。例如,1 3 7 2 4 6 8 5 8 的哈希值等于:
0*0! + 0*1! + 0*2! + 2*3! + 1*4! + 1*5! + 0*6! + 3*7! + (9-8)*8! = 55596 <9!
具体的原因可以去查查一些数学书,其中1 2 3 4 5 6 7 8 9 的哈希值是0 最小,8 7 6 5 4 3 2 1 0 的哈希值是(9!-1)最大,而其他值都在0 到 (9!-1) 中,且均唯一。