源代码BFS_DFS_v1.6.hpp

这次又有一点小的修改,主要是关于StateSpaceTreeSearch的第二个模板参数的。它是用于指定选用BFS还是DFS,原来我是让使用者选择BFSInserter和DFSInserter两者之一。后来想想,好象不应该让用户看到这两个结点插入策略,毕竟用户并不关心这一点。用户关心的仅是如何在BFS和DFS两者之间选择一个,所以我把选择的方法改为用一个bool常量来指定。

把原来的SearchInserter模板参数改为一个非类型模板参数,命名为UseBFS,当它为true时就用BFS,否则就用DFS。再定义一个SearchInserter模板来根据bool参数选择相应的BFSInserter或DFSInserter,代码如下:


// Filename: BFS_DFS_v1.6.hpp
#ifndef _BFS_DFS_HPP
#define _BFS_DFS_HPP

#include <list>
#include <vector>
#include <set>
#include <ext/hash_set>

using std::list;
using std::vector;
using std::set;
using __gnu_cxx::hash_set;
using __gnu_cxx::hash;

// 仿函式,用于不检查状态结点是否重复
template <class T>
struct NoCheckDup : std::unary_function<T, bool>
{
    bool operator() (const T&) const
    {
        return false;
    }
};

// 仿函式,用vector容器检查状态结点是否重复,线性复杂度
// 要求状态类提供operator==
template <class T>
class SequenceCheckDup : std::unary_function<T, bool>
{
    typedef vector<T> Cont;
    Cont states_;
public:
    bool operator() (const T& s)
    {
        typename Cont::iterator i =
            find(states_.begin(), states_.end(), s);
        if (i != states_.end())  // 状态已存在,重复
        {
            return true;
        }
        states_.push_back(s);  // 状态未重复,记录该状态
        return false;
    }
};

// 仿函式,用set容器检查状态结点是否重复,对数复杂度
// 要求状态类提供operator<
template <class T>
class OrderCheckDup : std::unary_function<T, bool>
{
    typedef set<T> Cont;
    Cont states_;
public:
    bool operator() (const T& s)
    {
        typename Cont::iterator i = states_.find(s);
        if (i != states_.end())  // 状态已存在,重复
        {
            return true;
        }
        states_.insert(i, s);  // 状态未重复,记录该状态
        return false;
    }
};

// 仿函式,用hash_set容器检查状态结点是否重复
// 要求状态类提供operator==以及hash()成员函数
template <class T>
class HashCheckDup : std::unary_function<T, bool>
{
    struct HashFcn
    {
        size_t operator()(const T& s) const { return s.hash(); }
    };
    typedef hash_set<T, HashFcn> Cont;
    Cont states_;
public:
    HashCheckDup() : states_(100, HashFcn()) {}
    bool operator() (const T& s)
    {
        if (states_.find(s) != states_.end())  // 状态已存在,重复
        {
            return true;
        }
        states_.insert(s);  // 状态未重复,记录该状态
        return false;
    }
};

// BFS算法对应的新结点插入策略
template <class Cont>
class BFSInserter
{
public:
    BFSInserter(Cont& c) : c_(c) {}
    typedef typename Cont::iterator iterator;
    typedef typename Cont::value_type value_type;
    void operator()(iterator it, const value_type& v) {
        c_.push_back(v);  //新结点插入到列表的末端,即未搜索的结点后
    }
private:
    Cont& c_;
};

// DFS算法对应的新结点插入策略
template <class Cont>
class DFSInserter
{
public:
    DFSInserter(Cont& c) : c_(c) {}
    typedef typename Cont::iterator iterator;
    typedef typename Cont::value_type value_type;
    void operator()(iterator it, const value_type& v) {
        c_.insert(++it, v);  //新结点插入到未搜索的结点前
    }
private:
    Cont& c_;
};

// 状态空间树搜索模板
// State:问题状态类,提供nextStep()和isTarget()成员函数
// UseBFS:可选择BFS或DFS,true为BFS,false为DFS,缺省为BFS
// CheckDup:状态查重算法,可选择NoCheckDup,HashCheckDup,OrderCheckDup等
template < class State, bool UseBFS = true,
    template <class> class CheckDup = NoCheckDup >
class StateSpaceTreeSearch
{
    template <class Cont, bool>
    struct SearchInserter
    {
        typedef DFSInserter<Cont> Inserter;
    };

    template <class Cont>
    struct SearchInserter<Cont, true>
    {
        typedef BFSInserter<Cont> Inserter;
    };

public:
    typedef list<State> Cont;
    typedef typename Cont::iterator iterator;
    typedef typename SearchInserter<Cont, UseBFS>::Inserter Inserter;

    template <class Func>
    int operator()(const State& initState, Func afterFindSolution) const
    // initState : 初始化状态,类State应提供成员函数nextStep()和isTarget(),
    //             nextStep()用vector<State>返回下一步可能的所有状态,
    //             isTarget()用于判断当前状态是否符合要求的答案;
    // afterFindSolution : 仿函式,在找到一个有效答案后调用之,它接受一个
    //                     const State&,并返回一个bool值,true表示停止搜索,
    //                     false表示继续搜索
    // return : 找到的答案数量
    {
        CheckDup<State> checkDup;
        Cont states;
        Inserter inserter(states);
        states.push_back(initState);
        iterator head = states.begin();  //指向下个搜索的结点
        vector<State> nextStates;
        int n = 0;  //记录找到的解答数量
        bool stop = false;
        while (!stop && head != states.end())
        {
            State s = *head;  //搜索一个结点
            nextStates.clear();
            s.nextStep(nextStates);  //从搜索点生成下一层结点
            for (typename vector<State>::iterator i = nextStates.begin();
                 i != nextStates.end(); ++i)
            {
                if (i->isTarget())
                {  // 找到一个目标状态
                    ++n;
                    if (stop = afterFindSolution(*i))  // 处理结果并决定是否停止
                    {
                        break;
                    }
                } else {  // 不是目标状态,判断是否放入搜索队列中
                    if (!checkDup(*i))  // 只将不重复的状态放入搜索队列
                    {
                        inserter(head, *i);
                    }
                }
            }
            ++head;  //指针移到下一个元素
        }
        return n;
    }
};

#endif


 相应地,使用者的代码也有所改变,以推箱子为例,如下:

// soko.cpp -- 推箱子主程序

#include <iostream>
#include "BFS_DFS_v1.6.hpp"
#include "SokoState_v1.h"

using namespace std;

bool printAnswer(const SokoState& s)
{
    s.printAnswer(cout);
    cout << endl;
    return true;
}

template <class T>
bool stopSearch(const T&)
{
    return true;
}

int main(int argc, char *argv[])
{
    SokoState initState;
    cin >> initState;
    cout << initState;
    StateSpaceTreeSearch<SokoState, true, OrderCheckDup> sokoSearch;
    int n = sokoSearch(initState, printAnswer);
    if (n == 0)
    {
        cout << "No answer." << endl;
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值