poj 1077 解题报告

最近学人工智能,要学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 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值