午夜稻草人

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

题目:

有N个传教士和N个野人要过河,现在有一条船只能承载M个人,在任何时刻,如果有野人和传教士在一起,必须要求传教士的人数多于或等于野人的人数(包括船上和两个岸边)。

设M为传教士的人数,C为野人的人数,当N=3, M=2时, 用状态空间法求解此问题的过程如下:

(1)设置状态变量并确定值域

S、C = N,B = { 0 , 1} (1表示在岸边),要求在船上S>=C且S+C <= M

初始状态       目标状态

  L R
S 3 0
C 3 0
B 1 0
  L R
S 0 3
C 0 3
B 0 1

                                              

 

 

 

(2)确定状态组,分别列出初始状态集和目标状态集

用三元组来表示(S , C , B)这里面都表示的是左岸状态

其中0<=S , C <= 3 , B∈{ 0 , 1}

(3 , 3 , 1)         (0 , 0 , 0)

初始状态表示全部成员在河的的左岸, 目标状态表示全部成员从河的左岸全部渡河完毕。

(3)定义并确定规则集合

        仍然以河的左岸为基点来考虑,把船从左岸划向右岸定义为Pij操作。其中,第一个下标i表示船载的传教士人数,第二个下标j表示船载的野人人数。同理,从右岸将船划回左岸称之为Qij操作,下标的定义同前。 则共有10种操作,操作集为:

                F={P10, P01,P11,P20,P02,Q10,Q01,Q11,Q20,Q02}

P10      if ( S , C , B=1 )   then ( S–1 , C , B –1 )

P01      if ( S , C , B=1 )   then ( S, C–1 , B –1 )

P11      if ( S , C , B=1 )   then ( S –1 , C–1 , B –1 )

P20      if ( S , C , B=1 )   then ( S –2 , C , B –1 )

P02      if ( S , C , B=1 )   then ( S, C–2 , B –1 )

Q10      if ( S , C , B=0 )   then ( S +1 , C , B+1 )

Q01      if ( S , C , B=0 )   then ( S, C+1 , B +1 )

Q11      if ( S , C , B=0 )   then ( S +1 , C +1, B +1 )

Q20       if ( S , C , B=0 )   then ( S +2 , C +2, B +1 )

Q02      if ( S , C, B=0 )   then ( S, C +2, B +1 )

(4)当状态数量不是很大时,画出合理的状态空间图(略)

 用广度优先的方法,求最少次数:

#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
#include <set>

using namespace std;

// N is the number of scholars/cannibals, M is the boat's capacity
int N,M;


class BoatState
{
public:
    int scholars;
    int cannibals;
};

class LeftRiverSideState
{
public:
    int scholars;
    int cannibals;
    bool isBoatOnStandby;
    int countTimes;
};

void createBoatState(vector<BoatState> &boatStates)
{
    //i cannibals, j scholars.
    for(int i=0; i<=M; ++i)
    {
        for(int j=0; j<=M; ++j)
        {
            if(i+j>0 && i+j<=M && (i<=j||j==0))
            {
                BoatState bState;
                bState.cannibals = i;
                bState.scholars = j;
                boatStates.push_back(bState);
            }
        }
    }
}


void changeState(LeftRiverSideState &lrsState, queue<LeftRiverSideState> &stateQueue, vector<BoatState> &boatStates)
{
    int countTimes = lrsState.countTimes + 1;
    if(lrsState.isBoatOnStandby)
    {
        for(vector<BoatState>::iterator iter=boatStates.begin(); iter!=boatStates.end(); ++iter)
        {
            if(lrsState.cannibals >= iter->cannibals && lrsState.scholars >= iter->scholars)
            {
                LeftRiverSideState tmpState;
                tmpState.cannibals = lrsState.cannibals - iter->cannibals;
                tmpState.scholars = lrsState.scholars - iter->scholars;
                tmpState.isBoatOnStandby = false;
                tmpState.countTimes = countTimes;
                stateQueue.push(tmpState);
            }
        }

    }
    else
    {

        for(vector<BoatState>::iterator iter=boatStates.begin(); iter!=boatStates.end(); ++iter)
        {
            if((N-lrsState.cannibals) >= iter->cannibals && (N-lrsState.scholars) >= iter->scholars)
            {
                LeftRiverSideState tmpState;
                tmpState.cannibals = lrsState.cannibals + iter->cannibals;
                tmpState.scholars = lrsState.scholars + iter->scholars;
                tmpState.isBoatOnStandby = true;
                tmpState.countTimes = countTimes;
                stateQueue.push(tmpState);
            }
        }
    }

}

int calculateMinTimes(queue<LeftRiverSideState> &stateQueue, vector<BoatState> &boatStates)
{
    vector<LeftRiverSideState> checkState;
    while(stateQueue.size() > 0)
    {
        LeftRiverSideState lrsState = stateQueue.front();
        stateQueue.pop();

        //end condition
        if(lrsState.cannibals==0 && lrsState.scholars==0 && lrsState.isBoatOnStandby == false)
        {
            return lrsState.countTimes;
        }

        //check left/right river side 
        if( (lrsState.cannibals>lrsState.scholars && lrsState.scholars!=0) || (N-lrsState.cannibals>N-lrsState.scholars && N-lrsState.scholars!=0) )
        {
            continue;
        }
        //check endless loop
        bool flag = false;
        for(vector<LeftRiverSideState>::iterator iter=checkState.begin(); iter!=checkState.end(); ++iter)
        {
            if(iter->cannibals==lrsState.cannibals && iter->isBoatOnStandby==lrsState.isBoatOnStandby && iter->scholars==lrsState.scholars)
            {
                flag = true;
                break;
            }
        }
        if(flag)
        {
            continue;
        }

        checkState.push_back(lrsState);
        changeState(lrsState, stateQueue, boatStates);


    }

    return -1;
}





int main(int argc, char** argv)
{
    int tc, T;

     freopen("E:/sample_input.txt", "r", stdin);

    cin >> T;
    for(tc = 0; tc < T; tc++)
    {
        cin >> N >> M;
        vector<BoatState> boatStates;
        
        createBoatState(boatStates);

        LeftRiverSideState lrsState;
        lrsState.cannibals = N;
        lrsState.scholars = N;
        lrsState.countTimes = 0;
        lrsState.isBoatOnStandby = true;
        queue<LeftRiverSideState> stateQueue;
        stateQueue.push(lrsState);

        int ret = calculateMinTimes(stateQueue, boatStates);
        if(ret != -1)
        {
            cout << ret << endl;
        }
        else
        {
            cout << "impossible" <<endl;
        }
    }

    return 0;
}

 

posted on 2015-04-13 18:22  午夜稻草人  阅读(703)  评论(0编辑  收藏  举报