这题和八数码十分相似,或许是我的遗留问题吧....敲完总是不过,各种错误。迟迟下不了手的原因就在于对空间的把握问题。要节约空间就必须设计一个好的hash函数,不然时空开销大。关键在于哈希怎么弄了?八位数--->87654321如果采用这么大的空间,空间消耗太大,许多内存都没采用,不行...
后来查了下资料,发现有康托展开恰好是结果全排列的哈希问题。有了康托展开之后,全排列的问题就可以采用最小的空间消耗了,8!=40320<<87654321;这样就可以用bfs了。
当然8个数也可以用8*3bit来表示。这样面向字节流的操作很快,而且空间更省。
根据百度百科理解的康托展开:
int cantor( int num )
{
int ret=0;bool h[9]={false};
for( int i=8;i>=2;i-- )
{
int k,t,b=1;
t=num;
while( t/10>0 ){
k=t/10;t/=10;b*=10;
}
h[k]=true;
num-=t*b;
int p=0;
for( int j=1;j<k;j++ )
if( h[j]==false )
p++;
ret+=p*fec[i-1];
}
//printf( "ret:%d\n",ret );
return ret;
}
当然还有逆康托展开,在理解了康托展开之后,逆展开也是很方便的。
康托展开什么意思呢?
就是当前的最左端的数,比其小的未用的数的个数,这些最小的数作为最左端的数,余下的数再进行全排列(只要看余下的位数,与可用的数的个数就可以了),比如54321,最左端是5,那么比他小的,最左端可以放4,3,2,1,都是未被使用过且小的。如果放下4,则剩下4个空填放1,2,3,5,种类数4!所以为4*4!;那么余下的4321,比他小的呢?这里就用到了递归,小化同样的情况。最终得出解。
理解了康托展开之后,逆康托展开也很方便了。
Code:
/*
ID:sevenst4
LANG:C++
PROG:msquare
*/
#include<stdio.h>
#include<cstdlib>
using namespace std;
struct node
{
int square[8];
char select;
}S,E;
int fec[10]={ 1,1,2,6,24,120,720,5040,40320 };
int hash[8]={1,2,3,4,8,7,6,5};
bool flag[50000]={false};
node queue[50000];
int pre[50000];
int nodeToNum( node a )
{
int ret=0;
for( int i=0;i<8;i++ )
ret=ret*10+a.square[hash[i]-1];
return ret;
}
int cantor( int num )
{
int ret=0;bool h[9]={false};
for( int i=8;i>=2;i-- )
{
int k,t,b=1;
t=num;
while( t/10>0 ){
k=t/10;t/=10;b*=10;
}
h[k]=true;
num-=t*b;
int p=0;
for( int j=1;j<k;j++ )
if( h[j]==false )
p++;
ret+=p*fec[i-1];
}
//printf( "ret:%d\n",ret );
return ret;
}
void init()
{
for( int i=0;i<8;i++ )
{
S.square[i]=hash[i];
scanf( "%d",&E.square[hash[i]-1] );
}
}
void print( node t,int foot )
{
char r[100];
int step=0;
for( int i=foot;pre[i]!=-1;i=pre[i] )
r[step++]=queue[i].select;
printf( "%d\n",step );
int s=0;
for( int i=step-1;i>=0;i-- )
{
s++;
if( s%60==0 )
printf( "\n" );
printf( "%c",r[i] );
}
if( s%60!=0 )
printf( "\n" );
}
node rotate( node a,int n )
{
if( n==1 )
{
for( int i=0;i<4;i++ )
{
int t=a.square[i];
a.square[i]=a.square[i+4];
a.square[i+4]=t;
}
}
else if( n==2 )
{
int t1=a.square[3];
int t2=a.square[7];
for( int i=3;i>=0;i-- )
{
a.square[i]=a.square[i-1];
a.square[i+4]=a.square[i+3];
}
a.square[0]=t1;
a.square[4]=t2;
}
else if( n==3 )
{
int t=a.square[1];
a.square[1]=a.square[5];
a.square[5]=a.square[6];
a.square[6]=a.square[2];
a.square[2]=t;
}
return a;
}
void bfs()
{
int head=0,foot=1;
queue[head]=S;
if( nodeToNum(S)==nodeToNum(E) )
{
printf( "0\n\n" );
return ;
}
flag[cantor(nodeToNum(S))]=true;
int step=-1;
pre[0]=-1;
while( head!=foot )
{
node cur=queue[head];
for( int i=1;i<=3;i++ )
{
node temp=rotate( cur,i );
temp.select=i+'A'-1;
int getnum=cantor(nodeToNum(temp));
if( flag[getnum]==false )
{
flag[getnum]=true;
pre[foot]=head;
queue[foot++]=temp;
}
if( nodeToNum(temp)==nodeToNum(E) )
{
print( temp,foot-1 );
return ;
}
}
head++;
}
}
int main()
{
freopen( "msquare.in","r",stdin );
freopen( "msquare.out","w",stdout );
init();
bfs();
return 0;
}