1. 程式人生 > >練習程式:算法系列14:狼、羊、菜和農夫過河問題

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

描述、思路

補充知識

參考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)))
            {
               ……
            }
        }
    }
}

執行結果

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