zoukankan      html  css  js  c++  java
  • 传教士-野人问题

    题目:

    有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;
    }
  • 相关阅读:
    Objective-C之NSArray(数组)默认排序与自定义排序
    Objective-C学习笔记之for( int )机制
    OC之NSString、NSMutableString学习笔记 常用方法
    换行回车的区别 2018-10-30
    Python头部2行 #!/usr/bin/python 和 #!/usr/bin/env 的区别 以及编码方式的指定 2018-10-23
    旧版Windows 睡眠与休眠 2018-10-18
    手机尺寸像素 PPI 2018-10-17
    VMvare 虚拟机扩容 2018-10-11
    批量判断网址能否访问 2018-10-04
    字符串的 strip()方法 2018-10-04
  • 原文地址:https://www.cnblogs.com/scarecrow-blog/p/4422909.html
Copyright © 2011-2022 走看看