poj1184 聪明的打字员

注:本解题报告里的有些思路不是由本人想出,是通过百度搜出来的。所以在此膜拜一下做出来的大牛们。

(个人认为) 这 是BFS的进阶题,以前做过的BFS都是按照操作一步步来,最终找出目标状态。这题巧妙的地方在于可以无视一些操作和把操作分类。比如说:光标左移是可以 无视的。因为光标移动是连续的,而且开始光标在最左边。也就是说,如果光标在第3个数的话,那么它一定经过0,1,2这几个位置。所以这时如果再考虑光标 左移是没有意义的。另外就是操作分类。所谓操作分类就是把操作分为两类(这两类分别对状态做出不同的影响):一类移动光标,另一类就是直接把数加到目标状 态,要注意的地方是,只有光标经过的地方才能进行加减。

这样一来,记录光标到过的位置就很重要了。一般能想到的是2^6种状态,但仔细考虑之后发现其实只有10种状态,分别是

0:0
1:0, 1
2:0, 1, 2
3:0, 1, 2, 3
4:0, 1, 2, 3, 4
5:0, 5
6:0, 1, 5
7:0, 1, 2, 5
8:0, 1, 2, 3, 5
9:0, 1, 2, 3, 4, 5

第6种状态之后会出现5这个位置,是因为swap1操作。

后记:

本题可以改进的地方有几个:

1.存储状态可以进一步压缩,据说只要10*6!就可以把所有状态存完

2.据说A*算法,但是我还没想到有效的评价函数(T_T)

3.看discuss,发现有人用双向BFS写出来了,看来我也要纠结一下如何用双向BFS写出来才行……

================传说中华丽的分割线=====================

 

 

#pragma warning(disable:4786)
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;

#define N 1000000

int start, end, v[ 6 ] ;
bool s[ N] [ 10 ] ;

struct node
{
    int state;//当前状态
    int step;//移动步数
    int visited;//光标到达过的位置
/*
0:0
1:0, 1
2:0, 1, 2
3:0, 1, 2, 3
4:0, 1, 2, 3, 4
5:0, 5
6:0, 1, 5
7:0, 1, 2, 5
8:0, 1, 2, 3, 5
9:0, 1, 2, 3, 4, 5
*/

} ;

void toArray( int n, int *v)
{
    for ( int i = 5 ; i >= 0 ; i--)
    {
        v[ i] = n % 10 ;
        n /= 10 ;
    }
}

int toNum( int *v)
{
    int ans, i;

    for ( i = 0 , ans = 0 ; i < 6 ; i++)
        ans = ans * 10 + v[ i] ;
   
    return ans;
}

//pos1:0 or 5, pos2:当前光标位置
int swapNum( int pos1, int pos2, int *v)
{
    int tmp, ans;

    //swap pos1 and pos2
    tmp = v[ pos1] ;
    v[ pos1] = v[ pos2] ;
    v[ pos2] = tmp;

    ans = toNum( v) ;

    //把数组恢复原样
    tmp = v[ pos1] ;
    v[ pos1] = v[ pos2] ;
    v[ pos2] = tmp;

    return ans;
}

int check( node& in)
{
    int tmp, res, i, a[ 6 ] ;

    toArray( in.state , a) ;
   
    tmp = in.visited ;
    if ( tmp <= 4 )
    {
        for ( i = tmp + 1 ; i < 6 ; i++)        
            if ( a[ i] != v[ i] ) return -1 ;

        for ( res = 0 , i = 0 ; i <= tmp; i++)
            res += abs ( a[ i] - v[ i] ) ;
    }
    else
    {
        tmp -= 5 ;
        for ( i = tmp + 1 ; i < 5 ; i++)    
            if ( a[ i] != v[ i] ) return -1 ;

        for ( res = 0 , i = 0 ; i <= tmp; i++)
            res += abs ( a[ i] - v[ i] ) ;   
       
        res += abs ( a[ 5 ] - v[ 5 ] ) ;
    }

    return res;
}

int BFS( )
{
    queue<node> q;
    node p;
    int ori, visited, tmp, a[ 6 ] , res, minimum = N;
    memset ( s, false , sizeof ( s) ) ;

    p.state = start;
    p.step = 0 ;
    p.visited = 0 ;
    q.push ( p) ;
    s[ start] [ 0 ] = true ;

    while ( !q.empty ( ) )
    {
        p = q.front ( ) ;
        q.pop ( ) ;

        ori = p.state ;
        visited = p.visited ;
        res = check( p) ;

        if ( res != -1 )
        {
            if ( minimum > res + p.step ) minimum = p.step + res;
        }

        p.step ++;
        if ( p.step >= minimum) continue ;//剪枝

        toArray( p.state , a) ;
        //swap0
        if ( p.visited > 0 )
        {
            if ( p.visited >= 5 ) tmp = swapNum( 0 , p.visited - 5 , a) ;
            else tmp = swapNum( 0 , p.visited , a) ;

            if ( !s[ tmp] [ p.visited ] )
            {
                p.state = tmp;
                q.push ( p) ;
                s[ tmp] [ p.visited ] = true ;
            }
        }

        //swap1
        if ( p.visited < 5 )
        {
            tmp = swapNum( 5 , p.visited , a) ;
            p.visited += 5 ;           
        }
        else tmp = swapNum( 5 , p.visited - 5 , a) ;

        if ( !s[ tmp] [ p.visited ] )
        {
            p.state = tmp;               
            q.push ( p) ;
            s[ tmp] [ p.visited ] = true ;
        }        

        //right
        p.state = ori;
        p.visited = visited;
        if ( p.visited < 5 )
        {            
            p.visited ++;
            if ( !s[ p.state ] [ p.visited ] ) q.push ( p) ;
        }
        else if ( p.visited < 9 )
        {
            p.visited ++;
            if ( !s[ p.state ] [ p.visited ] ) q.push ( p) ;
        }
    }

    return minimum;
}

int main( )
{
    while ( cin >> start >> end)
    {
        toArray( end, v) ;

        cout << BFS( ) << endl;
    }

    return 0 ;
}

你可能感兴趣的:(算法,struct,百度,存储)