最近学人工智能,要学A*算法,就重新做这道题经典的8数码问题,传说不做这道题人生不完整呢我之前是用的广搜暴力搞的,不过太慢了,还要说说我的hash方法,我是用康托展开来hash的,这个东西是算一个排列在所有排列大小排多少,比如(1,2,3)有6个排列,321是最大的就是第六个。还有就是康托展开的逆运算,就是知道是第几大的,算出这个排列来;
康托展开:
long cantor( int s[] )
{
int i , j , t ;
long num = 0 ;
for( i = 0 ; i < 9 - 1 ; i ++ )
{
t = 0 ;
for( j = i + 1 ; j < 9 ; j ++ )
if( s[j] < s[i] ) ++ t ;
num += fac[9-i-1] * t ;
}
return num ;
}
它的逆运算:
void uncantor( int s[] , int ct )
{
int i , j , t , r ;
bool p[10] = { 0 } ;
for( i = 0 ; i < 9 ; i ++ )
{
t = ct / fac[9 - i - 1] + 1 ;
ct %= fac[9 - i - 1] ;
r = 0 , j = 1 ;
while( 1 )
{
if( !p[j] ) r ++ ;
if( r == t ) break ;
j ++ ;
}
s[i] = j ; p[j] = 1 ;
}
}
就是这样的,,,
用爆搜的代码是这样的:
Problem: 1077 | User: 925695531 | |
Memory: 2404K | Time: 547MS | |
Language: C++ | Result: Accepted |
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
using namespace std;
int fac[10] ;
int pre[400000] ;
char dir[400000] ;
void init( )
{
fac[0] = 1 ;
for( int i = 1 ; i <= 9 ; i ++ )
fac[i] = i * fac[i-1] ;
}
long cantor( int s[] )
{
int i , j , t ;
long num = 0 ;
for( i = 0 ; i < 9 - 1 ; i ++ )
{
t = 0 ;
for( j = i + 1 ; j < 9 ; j ++ )
if( s[j] < s[i] ) ++ t ;
num += fac[9-i-1] * t ;
}
return num ;
}
void uncantor( int s[] , int ct )
{
int i , j , t , r ;
bool p[10] = { 0 } ;
for( i = 0 ; i < 9 ; i ++ )
{
t = ct / fac[9 - i - 1] + 1 ;
ct %= fac[9 - i - 1] ;
r = 0 , j = 1 ;
while( 1 )
{
if( !p[j] ) r ++ ;
if( r == t ) break ;
j ++ ;
}
s[i] = j ; p[j] = 1 ;
}
}
int main()
{
int tc[9] , ot , t , i;
char c[2] ;
bool ok = 0 ;
queue<int> q ;
init() ;
memset( pre , 0 , sizeof( pre ) ) ;
for( i = 0 ; i < 9 ; i ++ )
{
scanf( "%s" , c ) ;
if( c[0] == 'x' ) tc[i] = 9 ;
else tc[i] = c[0] - '0' ;
}
t = cantor( tc ) ;
pre[t] = -1 ;
q.push( t ) ;
while( !q.empty() )
{
ot = q.front() ;
q.pop() ;
if( ot == 0 ) { ok = 1 ; break ; }
uncantor( tc , ot ) ;
for( i = 0 ; i < 9 ; i ++ ) if( tc[i] == 9 ) break ;
if( i != 0 && i != 1 && i != 2 )
{
swap( tc[i] , tc[i-3] ) ;
t = cantor(tc) ;
if( !pre[t] )
{
pre[t] = ot ;
dir[t] = 'u' ;
q.push(t) ;
}
swap( tc[i] , tc[i-3] ) ;
}
if( i != 6 && i != 7 && i != 8 ) //down
{
swap( tc[i] , tc[i+3] ) ;
t = cantor( tc ) ;
if( !pre[t] )
{
pre[t] = ot ;
dir[t] = 'd' ;
q.push(t) ;
}
swap( tc[i] , tc[i+3] ) ;
}
if( i != 0 && i != 3 && i != 6 ) // left
{
swap( tc[i] , tc[i-1] ) ;
t = cantor( tc ) ;
if( !pre[t] )
{
pre[t] = ot ;
dir[t] = 'l' ;
q.push( t ) ;
}
swap( tc[i] , tc[i-1] ) ;
}
if( i != 2 && i != 5 && i != 8 ) // right
{
swap( tc[i] , tc[i+1] ) ;
t = cantor( tc ) ;
if( !pre[t] )
{
pre[t] = ot ;
dir[t] = 'r' ;
q.push(t) ;
}
swap( tc[i] , tc[i+1] ) ;
}
}
if( ok )
{
stack<char> s ;
while( pre[ot] != -1 )
{
s.push( dir[ot] ) ;
ot = pre[ot] ;
}
while( !s.empty() )
{
printf( "%c" , s.top() ) ;
s.pop() ;
}
}
else printf( "unsolvable\n" ) ;
}
然后我用了A*算法,,启发函数是网上找的:
Problem: 1077 | User: 925695531 | |
Memory: 6988K | Time: 16MS | |
Language: G++ | Result: Accepted |
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
using namespace std ;
int fac[10] ;
struct Node
{
int pre ;
int step ;
int h ;
char dir ;
bool vis ;
} node[400000] ;
char dir[400000] ;
bool vis[400000] ;
void init()
{
fac[0] = 1 ;
for( int i = 1 ; i <= 9 ; i ++ )
fac[i] = i * fac[i-1] ;
}
long cantor( int s[] )
{
int i , j , t ;
long num = 0 ;
for( i = 0 ; i < 9 - 1 ; i ++ )
{
t = 0 ;
for( j = i + 1 ; j < 9 ; j ++ )
if( s[j] < s[i] ) ++ t ;
num += fac[9-i-1] * t ;
}
return num ;
}
void uncantor( int s[] , int ct )
{
int i , j , t , r ;
bool p[10] = { 0 } ;
for( i = 0 ; i < 9 ; i ++ )
{
t = ct / fac[9 - i - 1] + 1 ;
ct %= fac[9 - i - 1] ;
r = 0 , j = 1 ;
while( 1 )
{
if( !p[j] ) r ++ ;
if( r == t ) break ;
j ++ ;
}
s[i] = j ; p[j] = 1 ;
}
}
class cmp
{
public:
bool operator()(int sa,int sb)
{
return node[sa].h+node[sa].step>node[sb].h+node[sb].step;
}
};
int h( int s[] )
{
int H = 0 ;
for( int i = 0 ; i < 9 ; i ++ )
{
if( s[i] != 9 ) H += abs ( double ( ( s[i] - 1 ) / 3 - i / 3 ) ) + abs ( double ( ( s[i] - 1 ) % 3 - i % 3 ) ) ;
//if( s[i] != 9 && i == s[i] - 1 ) H ++ ;
}
return H ;
}
bool AStar( int s[] )
{
int tc[9] , t , i , flag = 0 ;
//if( !isResolve( s ) ) return false ;
memset( vis , 0 , sizeof( vis ) ) ;
priority_queue< int , vector<int> , cmp > q ;
int temp = cantor( s ) ;
node[temp].pre = -1 ;
node[temp].step = 0 ;
node[temp].h = h( s ) ;
q.push( temp ) ;
while( !q.empty() )
{
temp = q.top() ;
q.pop() ;
if( temp == 0 ){
flag = 1 ;
break ;
}
if( vis[temp] ) continue ;
uncantor( tc , temp ) ;
for( i = 0 ; i < 9 ; i ++ ) if( tc[i] == 9 ) break ;
if( i != 0 && i != 1 && i != 2 )
{
swap( tc[i] , tc[i-3] ) ;
t = cantor(tc) ;
if( !node[t].pre )
{
node[t].pre = temp ;
node[t].step = node[temp].step + 1 ;
node[t].h = h( tc ) ;
dir[t] = 'u' ;
q.push(t) ;
}
swap( tc[i] , tc[i-3] ) ;
}
if( i != 6 && i != 7 && i != 8 )
{
swap( tc[i] , tc[i+3] ) ;
t = cantor( tc ) ;
if( !node[t].pre )
{
node[t].pre = temp ;
node[t].step = node[temp].step + 1 ;
node[t].h = h( tc ) ;
dir[t] = 'd' ;
q.push(t) ;
}
swap( tc[i] , tc[i+3] ) ;
}
if( i != 0 && i != 3 && i != 6 )
{
swap( tc[i] , tc[i-1] ) ;
t = cantor( tc ) ;
if( !node[t].pre )
{
node[t].pre = temp ;
node[t].step = node[temp].step + 1 ;
node[t].h = h( tc ) ;
dir[t] = 'l' ;
q.push(t) ;
}
swap( tc[i] , tc[i-1] ) ;
}
if( i != 2 && i != 5 && i != 8 )
{
swap( tc[i] , tc[i+1] ) ;
t = cantor( tc ) ;
if( !node[t].pre )
{
node[t].pre = temp ;
node[t].step = node[temp].step + 1 ;
node[t].h = h( tc ) ;
dir[t] = 'r' ;
q.push( t ) ;
}
swap( tc[i] , tc[i+1] ) ;
}
}
return flag ;
}
int main()
{
int tc[9] , ot = 0 , i ;
char ch ;
init() ;
for( i = 0 ; i < 9 ; i ++ )
{
cin >> ch ;
if( ch == 'x' ) tc[i] = 9 ;
else tc[i] = ch - '0' ;
}
if( AStar( tc ) )
{
stack < char > s ;
while( node[ot].pre != -1 )
{
s.push( dir[ot] ) ;
ot = node[ot].pre ;
}
while( !s.empty() )
{
cout << s.top() ;
s.pop() ;
}
cout << endl ;
}
else cout << "unsolvable" << endl ;
return 0 ;
}
然后我自己想了一个启发函数
结果是这样了:
Problem: 1077 | User: 925695531 | |
Memory: 6988K | Time: 0MS | |
Language: G++ | Result: Accepted |
#include <iostream>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
using namespace std ;
struct Node{
int pre , h , step ;
char dir ;
bool vis ;
} node[400000] ;
struct cmp
{
bool operator () ( int a , int b )
{
//return node[a].h + node[a].step > node[b].h + node[b].step ;
return node[a].h < node[b].h ;
}
} ;
int fac[10] ;
void init() ;
int cantor( int s[] ) ;
void uncantor( int s[] , int num ) ;
int h( int s[] ) ;
bool AStar( int s[] ) ;
int main()
{
int str[10] , State = 0 ;
char ch ;
init() ;
for( int i = 0 ; i < 9 ; i ++ )
{
cin >> ch ;
if( ch == 'x' ) str[i] = 9 ;
else str[i] = ch - '0' ;
}
if( AStar( str ) )
{
stack < char > s ;
while( node[State].pre != -1 )
{
s.push( node[State].dir ) ;
State = node[State].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 <= 9 ; i ++ )
fac[i] = i * fac[i-1] ;
}
int cantor( int s[] ) //康托展开
{
int num = 0 , t ;
for( int i = 0 ; i < 9 ; i ++ )
{
t = 0 ;
for( int j = i + 1 ; j < 9 ; j ++ )
if( s[i] > s[j] ) t ++ ;
num += fac[9 - i - 1] * t ;
}
return num ;
}
void uncantor( int s[] , int num ) //逆向康托展开
{
int j , t , r ;
bool p[10] ;
memset( p , 0 , sizeof( p ) ) ;
for( int i = 0 ; i < 9 ; i ++ )
{
t = num / fac[9 - i - 1] + 1 ;
num %= fac[9 - 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 < 9 ; i ++ )
//if( s[i] != 9 ) H += abs ( double ( ( s[i] - 1 ) / 3 - i / 3 ) ) +
// abs ( double ( ( s[i] - 1 ) % 3 - i % 3 ) ) ;
if( s[i] != 9 && i == s[i] - 1 ) H ++ ;
return H ;
}
bool AStar( int s[] ) //A*
{
int str[9] , flag = 0 , i , t ;
memset( node , 0 , sizeof( node ) ) ;
priority_queue< int , vector<int> , cmp > q ;
int temp = cantor( s ) ;
node[temp].step = 0 ;
node[temp].pre = -1 ;
node[temp].h = h( s ) ;
q.push( temp ) ;
while( !q.empty() )
{
temp = q.top() ;
q.pop() ;
if( temp == 0 ) {
flag = 1 ;
break ;
}
if( node[temp].vis ) continue ;
uncantor( str , temp ) ;
for( i = 0 ; i < 9 ; i ++ ) if( str[i] == 9 ) break ;
if( i != 0 && i != 1 && i != 2 )
{
swap( str[i] , str[i-3] ) ;
t = cantor( str ) ;
if( !node[t].pre )
{
node[t].pre = temp ;
node[t].step = node[temp].step + 1 ;
node[t].h = h( str ) ;
node[t].dir = 'u' ;
q.push( t ) ;
}
swap( str[i] , str[i-3] ) ;
}
if( i != 6 && i != 7 && i != 8 )
{
swap( str[i] , str[i+3] ) ;
t = cantor( str ) ;
if( !node[t].pre )
{
node[t].pre = temp ;
node[t].step = node[temp].step + 1 ;
node[t].h = h( str ) ;
node[t].dir = 'd' ;
q.push( t ) ;
}
swap( str[i] , str[i+3] ) ;
}
if( i != 0 && i != 3 && i != 6 )
{
swap( str[i] , str[i-1] ) ;
t = cantor( str ) ;
if( !node[t].pre )
{
node[t].pre = temp ;
node[t].step = node[temp].step + 1 ;
node[t].h = h( str ) ;
node[t].dir = 'l' ;
q.push( t ) ;
}
swap( str[i] , str[i-1] ) ;
}
if( i != 2 && i != 5 && i != 8 )
{
swap( str[i] , str[i+1] ) ;
t = cantor( str ) ;
if( !node[t].pre )
{
node[t].pre = temp ;
node[t].step = node[temp].step + 1 ;
node[t].h = h( str ) ;
node[t].dir = 'r' ;
q.push( t ) ;
}
swap( str[i] , str[i+1] ) ;
}
}
return flag ;
}