練習程序:算法系列14:狼、羊、菜和農夫過河問題

描述、思路

參考1:算法系列之十四:狼、羊、菜和農夫過河問題

補充知識

參考2:函數對象:關於仿函數、函數對象、ptr_fun
參考3:bind2nd使用

實現1

#include <iostream>
#include <deque>
#include <string>
#include <algorithm>
using namespace std;

const int action_count = 8; //一共有8種動作

int dfs_deep = 0;

int result_iter_num = 0; //打印結果時,遍歷的序號

enum State{HERE, THERE}; //對象的位置:此岸,彼岸

/* 動作的代號 */
enum Action{UNKNOWN, FARMER_GO, FARMER_GO_TAKE_WOLF,
            FARMER_GO_TAKE_SHEEP, FARMER_GO_TAKE_VEGETABLE,
            FARMER_BACK, FARMER_BACK_TAKE_WOLF,
            FARMER_BACK_TAKE_SHEEP, FARMER_BACK_TAKE_VEGETABLE};
/* 打印結果時,打印的與動作的代號對應的動作全名 */
string ActionName[action_count+1] = {"Unknown action",
    "Farmer go over river", "Farmer take wolf go over river",
    "Farmer take sheep go over river", "Farmer take vegetable go over river",
    "Farmer go back", "Farmer take wolf back go back",
    "Farmer take sheep go back", "Farmer take vegetable go back"};

/* 對象狀態,包含四元組狀態和已執行完的最後一個動作 */
struct ItemState
{
    State farmer, wolf, sheep, vegetable; //當前四元組的狀態(農夫、狼、羊、蔬菜的位置)
    Action curAction; //到達這一狀態的最後一個動作(已發生)
    ItemState()
    {
        farmer = HERE;
        wolf = HERE;
        sheep = HERE;
        vegetable = HERE;
        curAction = UNKNOWN;
    }

    ItemState(State f, State w, State s, State v)
    {
        farmer = f;
        wolf = w;
        sheep = s;
        vegetable = v;
        curAction = UNKNOWN;
    }

    bool IsFinalState() //當前動作是否是結束狀態
    {
        if((farmer==THERE) && (wolf==THERE) &&
           (sheep==THERE) && (vegetable==THERE))
        {
            return true;
        }
        return false;
    }

    friend bool operator == (const ItemState& is1, const ItemState& is2);

};

bool operator == (const ItemState& is1, const ItemState& is2)
{
    if((is1.farmer == is2.farmer) && (is1.sheep == is2.sheep) &&
       (is1.vegetable == is2.vegetable) && (is1.wolf == is2.wolf))
    {
        return true;
    }
    return false;
}

typedef bool (*ProcessNextFuncPtr)(const ItemState& current, ItemState& next);//函數指針

struct ActionProcess //動作處理映射結構
{
    Action act; //要執行的動作
    ProcessNextFuncPtr processFunc;//要執行的動作對應的處理流程函數指針

};

void PrintResult(const deque<ItemState> states)
{
    cout << "Find Result " << ++result_iter_num << ":" << endl;
    for(int i = 0; i < states.size(); ++i)
    {

        cout << ActionName[states[i].curAction] << ", item states is : "
             << states[i].farmer << ", " << states[i].wolf << ", "
             << states[i].sheep << ", " << states[i].vegetable << endl;
    }

}
/* 去除不合乎要求的狀態,判斷狼、羊不能獨處,羊、菜不能獨處的情況 */
bool IsCurrentStateValid(const ItemState& next)
{
    if(next.wolf == next.sheep)
    {
        if(next.wolf != next.farmer)
        {
            return false;
        }
    }
    if(next.sheep == next.vegetable)
    {
        if(next.sheep != next.farmer)
        {
            return false;
        }
    }
    return true;
}


/* 判斷兩個狀態是否相同 */
bool IsSameItemState(ItemState& curItemState, ItemState& newState)
{
    if(((curItemState.farmer) == (newState.farmer)) &&
       ((curItemState.wolf) == (newState.wolf)) &&
       ((curItemState.sheep) == (newState.sheep)) &&
       ((curItemState.vegetable) == (newState.vegetable)))
    {
        return true;
    }
    return false;
}


/* 避免重複處理狀態,檢查新狀態是否和狀態路徑上已經處理過的狀態有重複 */
bool IsProcessedState(deque<ItemState>& states, ItemState& newState)
{
    for(int i = 0; i < states.size(); ++i)
    {
        if(states[i] == newState)
        {
            return true;
        }

    }
    return false;
}

/* 處理流程:農夫過河 */
bool ProcessFarmerGo(const ItemState& current, ItemState& next)
{
    //去除不可能的動作
    if(current.farmer == THERE)
    {
        return false;
    }
    next = current;
    next.farmer = THERE;
    next.curAction = FARMER_GO;
    return true;
}

/* 處理流程:農夫+狼過河 */
bool ProcessFarmerGoTakeWolf(const ItemState& current, ItemState& next)
{
    //去除不可能的動作,如果農夫在對岸,或者狼在對岸,則該動作不可進行
    if((current.farmer == THERE)|| (current.wolf == THERE))
    {
        return false;
    }
    next = current;
    next.farmer = THERE;
    next.wolf = THERE;
    next.curAction = FARMER_GO_TAKE_WOLF;
    return true;
}

/* 處理流程:農夫+羊過河 */
bool ProcessFarmerGoTakeSheep(const ItemState& current, ItemState& next)
{
    //去除不可能的動作
    if((current.farmer == THERE)||(current.sheep == THERE))
    {
        return false;
    }
    next = current;
    next.farmer = THERE;
    next.sheep = THERE;
    next.curAction = FARMER_GO_TAKE_SHEEP;
    return true;
}

/* 處理流程:農夫+菜過河 */
bool ProcessFarmerGoTakeVegetable(const ItemState& current, ItemState& next)
{
    //去除不可能的動作
    if((current.farmer == THERE)||(current.vegetable == THERE))
    {
        return false;
    }
    next = current;
    next.farmer = THERE;
    next.vegetable = THERE;
    next.curAction = FARMER_GO_TAKE_VEGETABLE;
    return true;
}

/* 處理流程:農夫返回 */
bool ProcessFarmerBack(const ItemState& current, ItemState& next)
{
    //去除不可能的動作
    if(current.farmer == HERE)
    {
        return false;
    }
    next = current;
    next.farmer = HERE;
    next.curAction = FARMER_BACK;
    return true;
}

/* 處理流程:農夫+狼返回 */
bool ProcessFarmerBackTakeWolf(const ItemState& current, ItemState& next)
{
    //去除不可能的動作,如果農夫在對岸,或者狼在對岸,則該動作不可進行
    if((current.farmer == HERE)|| (current.wolf == HERE))
    {
        return false;
    }
    next = current;
    next.farmer = HERE;
    next.wolf = HERE;
    next.curAction = FARMER_BACK_TAKE_WOLF;
    return true;
}

/* 處理流程:農夫+羊返回 */
bool ProcessFarmerBackTakeSheep(const ItemState& current, ItemState& next)
{
    //去除不可能的動作
    if((current.farmer == HERE)||(current.sheep == HERE))
    {
        return false;
    }
    next = current;
    next.farmer = HERE;
    next.sheep = HERE;
    next.curAction = FARMER_BACK_TAKE_SHEEP;
    return true;
}

/* 處理流程:農夫+菜返回 */
bool ProcessFarmerBackTakeVegetable(const ItemState& current, ItemState& next)
{
    //去除不可能的動作
    if((current.farmer == HERE)||(current.vegetable == HERE))
    {
        return false;
    }
    next = current;
    next.farmer = HERE;
    next.vegetable = HERE;
    next.curAction = FARMER_BACK_TAKE_VEGETABLE;
    return true;
}

/* 動作處理映射表 */
ActionProcess actMap[action_count] =
{
    {FARMER_GO, ProcessFarmerGo},
    {FARMER_GO_TAKE_WOLF, ProcessFarmerGoTakeWolf},
    {FARMER_GO_TAKE_SHEEP, ProcessFarmerGoTakeSheep},
    {FARMER_GO_TAKE_VEGETABLE, ProcessFarmerGoTakeVegetable},
    {FARMER_BACK, ProcessFarmerBack},
    {FARMER_BACK_TAKE_WOLF, ProcessFarmerBackTakeWolf},
    {FARMER_BACK_TAKE_SHEEP, ProcessFarmerBackTakeSheep},
    {FARMER_BACK_TAKE_VEGETABLE, ProcessFarmerBackTakeVegetable},
};

/* 遞歸,DFS, 窮舉+剪枝,搜索並打印解 */
void ProcessState(deque<ItemState>& states)//執行動作,每次執行有8種選擇
{
    //每次從狀態路徑中取出最後一個狀態,爲當前狀態
    ItemState current = states.back();
    if(current.IsFinalState())
    {
        PrintResult(states);
        return;
    }
    ItemState next = ItemState();
    for(int i = 0; i < action_count; ++i)
    {
        if(actMap[i].processFunc(current, next))
        {
            if(IsCurrentStateValid(next) && (!IsProcessedState(states, next)))
            {
                states.push_back(next);//在尾部追加新狀態

                //cout << ++dfs_deep << endl;
                ProcessState(states);//調用自身
                states.pop_back();//刪除尾部的狀態,遞歸依次返回

            }
        }

    }
}

int main()
{
    ItemState startItemState = ItemState();
    deque<ItemState> states;
    states.push_back(startItemState);
    /* 遞歸,DFS, 窮舉+剪枝,搜索並打印解 */
    ProcessState(states);
    return 0;
}

實現2

用參考資料的bind2nd方法的話,新增該函數:

bool IsProcessedState_bind(deque<ItemState>& states, ItemState& newState)
{

    deque<ItemState>::iterator it =
        find_if(states.begin(), states.end(),
                bind2nd(ptr_fun(IsSameItemState),newState));
    return (it!=states.end());

}

!注意:IsSameItemState函數需要修改參數類型,不可爲引用,否則編譯不通過。修改IsSameItemState:

/*修改一下參數類型,去掉引用即可,函數體不變*/
bool IsSameItemState(ItemState curItemState, ItemState newState)
{
    ……
}

修改遞歸函數:


void ProcessState(deque<ItemState>& states)
{
    ……
    for(int i = 0; i < action_count; ++i)
    {
        if(actMap[i].processFunc(current, next))
        {
        /*修改此處,調用新增的IsProcessedState_bind,其他內容不變*/
            if(IsCurrentStateValid(next) && (!IsProcessedState_bind(states, next)))
            {
               ……
            }
        }
    }
}

運行結果

兩種實現運行結果是相同的:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章