【例子】一个小益智游戏(过河游戏)的求解

问题如下:

一对父母带着2个女儿和2个儿子,一个警察带着一个小偷,他们都要过河去对岸。

只有一条船,每次最多只能乘坐2个人,并且只有爸爸、妈妈、警察可以开船。

小偷不能在离开警察的情况下和其他人在一起;儿子不能在没有爸爸的情况下和妈妈在一起;女儿不能在没有妈妈的情况下和爸爸在一起。

递归法实现如下:

#include <stdio.h>

#define TRUE 1
#define FALSE 0

class RiverCrosser
{
    #define PERSON_NUM  8
    #define START_STATE  0
    #define FINISH_STATE 1
    
    enum PersonNo 
    {
        DAD,
        BOY1,
        BOY2,
        MUM,
        GIRL1,
        GIRL2,
        POLICE,
        THIEF,
        BOAT
    
} ;
    
    struct Record
    
{
        #define    RECORD_MAX (1000)
        
        Record()
        {
            initRecord();
        
}

        void recordState( int state )
        
{
            __beginState[__steps] = state; 
            ++__steps;
        
}
        
        bool isStateExist( int state ) const        //判断当前状态是否已经被记录
        
{
            for ( int i = 0; i < __steps; ++i )
            {
                if ( state == __beginState[i] )
                {
                    return true;
                
}
            }

            return false;
        }
        
        void initRecord()    //初始化记录数组
        
{
            __steps = 1;
            __beginState[0] = 0x1ff;
        
}
        
        int __steps;
        int __beginState[RECORD_MAX];    //记录发生过的状态
    };

public:
    //初始状态:人和船都在河岸的这边
    RiverCrosser():_begin(0x1ff)
    
{
    
}
    
    int crossing();        //递归完成渡河操作

    static void printfInfo( int state );    //输出河岸这边的信息

private:
    bool isCrossOK() const;        //判断渡河是否成功

    static bool isAllowed( int state );    //此次渡河是否允许    
    static bool canCross( int i )        //是否有能力渡河(只有爸爸妈妈警察能开船)
    
{
        return (i == POLICE) || (i == DAD) || (i == MUM);    
    
}
    
    int _begin;    //高位表示船的位置
    Record _record;
    
    const static int personMask[];
    const static char * personName[];
};

const int RiverCrosser::personMask[] = 
{  1, 2, 4, 8, 16, 32, 64, 128, 256  } ;
const char* RiverCrosser::personName[] = 
{  "DAD-----", "BOY1----", "BOY2----", "MUM-----", "GIRL1---", "GIRL2---", 
                                        "POLICE--", "THIEF---", "BOAT----", "****----" 
} ;

///
bool RiverCrosser::isCrossOK() const
{
    return _begin == 0;
}

bool RiverCrosser::isAllowed( int state )
{
    if ( (state & personMask[THIEF]) && !(state & personMask[POLICE])  )    //小偷在且警察不在
    {        
        if ( state & (~personMask[THIEF]&0xff) )
        {
            return false;
        
}
    }

    if ( (state & personMask[DAD])  && !(state & personMask[MUM]) ) //爸爸在并且妈妈不在
    
{
        if ( (state & personMask[GIRL1]) || (state & personMask[GIRL2] ) )  //至少有一个女儿在
        {
            return false;    
        
}
    }

    if ( (state & personMask[MUM]) && !(state & personMask[DAD]) ) //妈妈在并且爸爸不在
    
{
        if ( (state & personMask[BOY1] ) || (state & personMask[BOY2] ) )  //至少有一个儿子在
        {
            return false;    
        
}
    }
    return true;
}

void RiverCrosser::printfInfo( int state )
{
    for ( int i = 0; i <= PERSON_NUM; ++i )
    {
        if ( state & personMask[i] )
        {
            printf( personName[i] );            
        
}         
        else
        
{
            printf( personName[PERSON_NUM+1] );        
        
}
    }
    printf( " " );
}

//递归完成每次过河操作
int RiverCrosser::crossing()
{     
    if ( isCrossOK() )    //渡河是否成功
    {
        return TRUE;
    
}     

    //临时保存当前状态
    const int oldBegin = _begin;
    const int oldEnd = oldBegin ^ 0x1ff;
        
    for ( int P1 = 0; P1 < PERSON_NUM; ++P1 )
    for ( int P2 = 0; P2 <=  P1; ++P2  )        //P1 == P2时,表示只有一个人渡河
    
{
        int currState[2] = { oldBegin, oldBegin 
} ;
        currState[(oldBegin&personMask[BOAT])>>BOAT] = oldEnd;
        
        if ( (currState[START_STATE] & personMask[P1])  && (currState[START_STATE] & personMask[P2])  && ( canCross(P1)||canCross(P2) ) )
        
{     
            currState[START_STATE] ^= (personMask[P1] | personMask[BOAT]);
            currState[FINISH_STATE] ^= (personMask[P1] | personMask[BOAT]);
            
            if ( P1 != P2 )
            {
                currState[START_STATE] ^= personMask[P2];
                currState[FINISH_STATE] ^= personMask[P2];
            
}

            if ( isAllowed( currState[START_STATE] ) && isAllowed( currState[FINISH_STATE] ) ) //过河后是否符合要求
            
{
                //允许渡河                
                if (  _record.isStateExist( currState[(oldEnd&personMask[BOAT])>>BOAT] ) )//判断状态是否存在
                {
                    //忽略此次渡河
                    continue;
                
}
                                
                //成功渡河,修改当前状态,并做记录
                _begin = currState[(oldEnd&personMask[BOAT])>>BOAT];
                
                _record.recordState( _begin );        //记录
                
                if ( crossing() )    //准备下一次渡河
                
{         
                    //输出渡河经过
                    printfInfo( oldBegin );
                    return TRUE;
                
}                                 
            }            
        }
    }
    return FALSE;
}

int main(int argc, char* argv[])
{
    RiverCrosser riverCross;
    riverCross.crossing();
    return 0;
}

P.S. 用递归实现,效率可能较低,一时也没想到好方法。 

输出每次渡河后的状态(从下往上):

****----****----****----****----****----****----POLICE--THIEF---BOAT----
****----****----****----****----****----****----****----THIEF---****----
****----****----****----****----****----GIRL2---POLICE--THIEF---BOAT----
****----****----****----****----****----GIRL2---****----****----****----
****----****----****----MUM-----GIRL1---GIRL2---****----****----BOAT----
****----****----****----****----GIRL1---GIRL2---****----****----****----
DAD-----****----****----MUM-----GIRL1---GIRL2---****----****----BOAT----
****----****----****----MUM-----GIRL1---GIRL2---****----****----****----
****----****----****----MUM-----GIRL1---GIRL2---POLICE--THIEF---BOAT----
****----****----****----****----GIRL1---GIRL2---POLICE--THIEF---****----
DAD-----****----****----MUM-----GIRL1---GIRL2---POLICE--THIEF---BOAT----
****----****----****----MUM-----GIRL1---GIRL2---POLICE--THIEF---****----
DAD-----****----BOY2----MUM-----GIRL1---GIRL2---POLICE--THIEF---BOAT----
DAD-----****----BOY2----MUM-----GIRL1---GIRL2---****----****----****----
DAD-----BOY1----BOY2----MUM-----GIRL1---GIRL2---POLICE--****----BOAT----
DAD-----BOY1----BOY2----MUM-----GIRL1---GIRL2---****----****----****----
DAD-----BOY1----BOY2----MUM-----GIRL1---GIRL2---POLICE--THIEF---BOAT----

 

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值