做完八数码之后我还想做难一点的东西,因为八数码直接爆搜就可以了,所以想做一下爆搜不能做的东西,十五数码如果爆搜的话有15!种状态,不可能存下的;
我的思路是不存那么多状态,我把所有的状态hash到10000大小的vector数组里面,每次搜索不可能吧所有的状态都遍历完,所以不会爆内存的,然后存路径是用
链表做的,将后面扩展到的状态指向前一个状态,在搜索到的时候就从最后一个向前遍历,然后把方向存在一个栈中,输出就可以了
下面粘代码:
#include <iostream>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
using namespace std ;
struct Node {
int h , step ;
long long key ;
char dir ;
Node * pre ;
} ;
struct cmp {
bool operator () ( Node a , Node b ) {
return a.h < b.h ;
}
} ;
long long fac[17] ;
vector < long long > Hash[10000] ;
Node *END ;
void init() ;
long long cantor( int s[] ) ;
void uncantor( int s[] , long long num ) ;
int h( int s[] ) ;
bool AStar( int s[] ) ;
bool check( long long ) ;
int main()
{
int str[16] ;
char ch ;
init() ;
memset( Hash , 0 , sizeof( Hash ) ) ;
for( int i = 0 ; i <= 15 ; i ++ )
{
cin >> ch ;
if( ch == 'x' ) str[i] = 16 ;
else if( ch >= '0' && ch <= '9' ) str[i] = ch - '0' ;
else str[i] = 10 + ch - 'A' ;
}
if( AStar( str ) )
{
stack < char > s ;
while( END->pre != NULL )
{
s.push( END->dir ) ;
END = END->pre ;
}
while( !s.empty() )
{
cout << s.top() ;
s.pop() ;
}
cout << endl ;
}
else cout << "unsolvable" << endl ;
return 0 ;
}
void init()
{
fac[0] = 1 ;
for( int i = 1 ; i <= 16 ; i ++ )
fac[i] = i * fac[i-1] ;
}
long long cantor( int s[] )
{
long long num = 0 , t ;
for( int i = 0 ; i < 16 ; i ++ )
{
t = 0 ;
for( int j = i + 1 ; j < 16 ; j ++ )
if( s[i] > s[j] ) t ++ ;
num += fac[16 - i - 1] * t ;
}
return num ;
}
void uncantor( int s[] , long long num )
{
long long j , t , r ;
bool p[17] ;
memset( p , 0 , sizeof( p ) ) ;
for( int i = 0 ; i < 16 ; i ++ )
{
t = num / fac[16 - i - 1] + 1 ;
num %= fac[16 - i - 1] ;
r = 0 , j = 1 ;
while( 1 )
{
if( !p[j] ) r ++ ;
if( r == t ) break ;
j ++ ;
}
s[i] = j ; p[j] = 1 ;
}
}
int h( int s[] )
{
int H = 0 ;
for( int i = 0 ; i < 16 ; i ++ )
if( s[i] != 16 && i == s[i] - 1 ) H ++ ;
return H ;
}
bool check( long long num )
{
int key = num % 10000 ;
bool flag = 0 ;
for( int i = 0 ; i < Hash[key].size() ; i ++ )
if( Hash[key][i] == num ) {
flag = 1 ;
break ;
}
return ( 1 - flag ) ;
}
bool AStar( int s[] )
{
int str[16] , flag = 0 , i ;
long long t ;
priority_queue< Node , vector< Node > , cmp > q ;
Node * start = new Node ;
start->key = cantor( s ) ;
start->pre = NULL ;
start->h = h( s ) ;
start->step = 0 ;
start->dir = '0' ;
int num = start->key % 10000 ;
Hash[num].push_back( start->key ) ;
q.push( *start ) ;
while( !q.empty() )
{
Node * temp = new Node ;
* temp = q.top() ;
q.pop() ;
if( temp->key == 0 ){
flag = 1 ;
END = temp ;
break ;
}
uncantor( str , temp->key ) ;
for( i = 0 ; i < 16 ; i ++ ) if( str[i] == 16 ) break ;
if( i != 0 && i != 1 && i != 2 && i != 3 )
{
swap( str[i] , str[i-4] ) ;
t = cantor( str ) ;
if( check( t ) )
{
Node *tmp = new Node ;
tmp->dir = 'u' ;
tmp->h = h( str ) ;
tmp->key = t ;
tmp->pre = temp ;
tmp->step = temp->step + 1 ;
num = t % 10000 ;
Hash[num].push_back( t ) ;
q.push( *tmp ) ;
}
swap( str[i] , str[i-4] ) ;
}
if( i != 12 && i != 13 && i != 14 && i != 15 )
{
swap( str[i] , str[i+4] ) ;
t = cantor( str ) ;
if( check( t ) )
{
Node *tmp = new Node ;
tmp->dir = 'd' ;
tmp->h = h( str ) ;
tmp->key = t ;
tmp->pre = temp ;
tmp->step = temp->step + 1 ;
num = t % 10000 ;
Hash[num].push_back( t ) ;
q.push( *tmp ) ;
}
swap( str[i] , str[i+4] ) ;
}
if( i != 0 && i != 4 && i != 8 && i != 12 )
{
swap( str[i] , str[i-1] ) ;
t = cantor( str ) ;
if( check( t ) )
{
Node *tmp = new Node ;
tmp->dir = 'l' ;
tmp->h = h( str ) ;
tmp->key = t ;
tmp->pre = temp ;
tmp->step = temp->step + 1 ;
num = t % 10000 ;
Hash[num].push_back( t ) ;
q.push( *tmp ) ;
}
swap( str[i] , str[i-1] ) ;
}
if( i != 3 && i != 7 && i != 11 && i != 15 )
{
swap( str[i] , str[i+1] ) ;
t = cantor( str ) ;
if( check( t ) )
{
Node *tmp = new Node ;
tmp->dir = 'r' ;
tmp->h = h( str ) ;
tmp->key = t ;
tmp->pre = temp ;
tmp->step = temp->step + 1 ;
num = t % 10000 ;
Hash[num].push_back( t ) ;
q.push( *tmp ) ;
}
swap( str[i] , str[i+1] ) ;
}
}
return flag ;
}