您的位置:首页 > 其它

poj 1077 解题报告

2013-02-27 21:28 316 查看
最近学人工智能,要学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: 1077User:
925695531
Memory: 2404KTime: 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: 1077User:
925695531
Memory: 6988KTime: 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: 1077User:
925695531
Memory: 6988KTime: 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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: