转帖地址http://blog.csdn.net/alai04/archive/2006/05/31/765958.aspx
// ----------------------------------------------------------------------------
// SokoState_v1.cpp -- SokoState类的实现文件,第一版
#if 0
#include "SokoState_v1.h"
#include <iterator>
#include <string>
#include <memory>
#include <stdexcept>
using namespace std;
inline unsigned char SokoState::mapChar(Point p) const
{
if (isWall(p))
return CharWall;
else if (isBox(p))
return isDest(p) ? CharInDest : CharBox;
else if (isSoko(p))
return isDest(p) ? CharSokoInDest : CharSoko;
else if (isDest(p))
return CharDest;
else
return CharSpace;
}
void SokoState::checkSoko(stack<Point>& ps, Point p)
{
if (isPureSpace(p))
{
map_[p.x_][p.y_] |= FlagSoko;
ps.push(p);
}
}
void SokoState::stateEq()
{
int i, j;
for (i = 1; i < rows_-1; i++)
{
for (j = 1; j < cols_-1; j++)
{
if (isSoko(Point(i, j))) break;
}
if (j < cols_-1) break;
}
stack<Point> points;
Point p(i, j);
points.push(p);
while (!points.empty())
{
p = points.top();
points.pop();
checkSoko(points, p.up());
checkSoko(points, p.down());
checkSoko(points, p.left());
checkSoko(points, p.right());
}
}
bool SokoState::moveBox(SokoState& r, Point box, Point soko, Point nBox,
char d) const
{
if (!isSoko(soko) || !isSpace(nBox))
return false;
r = *this;
for (int i = 0; i < r.rows_; i++) //清除soko标志
{
for (int j = 0; j < r.cols_; j++)
{
r.map_[i][j] &= ~FlagSoko;
}
}
r.map_[box.x_][box.y_] &= ~FlagBox; //移动箱子
r.map_[box.x_][box.y_] |= FlagSoko;
r.map_[nBox.x_][nBox.y_] |= FlagBox;
r.stateEq();
r.steps_.push_back(SokoStep(box.x_, box.y_, d));
return true;
}
void SokoState::nextStep(vector<SokoState>& vs) const
{
SokoState newState;
for (int i = 1; i < rows_-1; i++)
{
for (int j = 1; j < cols_-1; j++)
{
Point p(i, j);
if (!isBox(p))
continue;
if (moveBox(newState, p, p.down(), p.up(), 'U'))
vs.push_back(newState);
if (moveBox(newState, p, p.up(), p.down(), 'D'))
vs.push_back(newState);
if (moveBox(newState, p, p.right(), p.left(), 'L'))
vs.push_back(newState);
if (moveBox(newState, p, p.left(), p.right(), 'R'))
vs.push_back(newState);
}
}
}
bool SokoState::isTarget() const
{
for (int i = 1; i < rows_-1; i++)
{
for (int j = 1; j < cols_-1; j++)
{
Point p(i, j);
if (isDest(p) != isBox(p))
return false;
}
}
return true;
}
void SokoState::printAnswer(ostream& os) const
{
copy(steps_.begin(), steps_.end(), ostream_iterator<SokoStep>(os, " "));
}
bool SokoState::operator< (const SokoState& other) const
{
if (rows_ < other.rows_)
return true;
if (rows_ > other.rows_)
return false;
if (cols_ < other.cols_)
return true;
if (cols_ > other.cols_)
return false;
for (int i = 0; i < rows_; i++)
{
for (int j = 0; j < cols_; j++)
{
if (map_[i][j] < other.map_[i][j])
return true;
if (map_[i][j] > other.map_[i][j])
return false;
}
}
return false;
}
ostream& operator<< (ostream& os, const SokoState& s)
{
for (int i = 0; i < s.rows_; i++)
{
for (int j = 0; j < s.cols_; j++)
{
os << s.mapChar(SokoState::Point(i, j));
}
os << "/n";
}
os << "------------------------" << endl;
return os;
}
istream& operator>> (istream& is, SokoState& s)
{
is >> s.rows_;
if (s.rows_ < MIN_ROWS || s.rows_ > MAX_ROWS)
{
throw invalid_argument("rows of soko game error.");
}
is >> s.cols_;
if (s.cols_ < MIN_COLS || s.cols_ > MAX_COLS)
{
throw invalid_argument("cols of soko game error.");
}
string str;
getline(is, str); // 滤过第一行的换行
for (int i = 0; i < s.rows_; i++)
{
getline(is, str);
for (int j = 0; j < s.cols_; j++)
{
s.map_[i][j] = 0;
switch (str[j]) {
case SokoState::CharBox :
s.map_[i][j] |= SokoState::FlagBox;
break;
case SokoState::CharWall :
s.map_[i][j] |= SokoState::FlagWall;
break;
case SokoState::CharSpace :
break;
case SokoState::CharDest :
s.map_[i][j] |= SokoState::FlagDest;
break;
case SokoState::CharInDest :
s.map_[i][j] |= SokoState::FlagDest | SokoState::FlagBox;
break;
case SokoState::CharSoko :
s.map_[i][j] |= SokoState::FlagSoko;
break;
case SokoState::CharSokoInDest :
s.map_[i][j] |= SokoState::FlagSoko | SokoState::FlagDest;
break;
default :
throw invalid_argument(
string("char of soko game error: ") + str );
}
}
}
s.stateEq();
return is;
}
// ----------------------------------------------------------------------------
// soko.cpp -- 推箱子主程序
#include <iostream>
//#include "BreadthFirstSearch.hpp"
#include "bfs.h"
#include "SokoState_v1.h"
using namespace std;
bool printAnswer(const SokoState& s)
{
s.printAnswer(cout);
cout << endl;
return true;
}
/*
输入:
9 9
WWWWWWWWW
WWWSSSWWW
WWSSSSSSW
WWIWIWISW
WWSWKBSWW
WWSWSWDWW
WSSSSSSWW
WSSSWSSWW
WWWWWWWWW
*/
int main(int argc, char *argv[])
{
SokoState initState;
cin >> initState;
cout << initState;
OrderCheckDup<SokoState> checkDup;
int n = BreadthFirstSearch(initState, printAnswer, checkDup);
if (n == 0)
{
cout << "No answer." << endl;
}
return 0;
}
//本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/alai04/archive/2006/05/31/765958.aspx
#endif
/*
在引入boost.Multi_index容器,我想有必要先整理一下DFS/BFS的代码。主要的修改是,
不再使用queue容器和stack容器,而用list容器来替换它们。原因是,queue和stack容器
会把已搜索过的结点删除掉,而我们如果要在容器内进行查重的话,就必须保留所有结点
,所以不能使用这两种容器。
一开始我也想过使用vector容器,不过由于我们最终的目标是Multi_index容器,它不能象
vector那样进行随机访问,它只能实现list容器的功能,为了便于向Multi_index过渡,最
终我还是选择了list。
没有了queue和stack,我们就要用一个iterator来区分list中那些已搜索与未搜索的结点。
我把已搜索和未搜索的结点分别放在list的两端,而这个iterator指向它们的分界线,即
iterator之前的结点为已搜索结点,之后的结点为未搜索结点。当我们需要取出下一个结
点来处理时,只要把iterator后移一下就可以了;对当前结点调用nextStep()所得到的下
一层结点,则要视DFS或BFS来决定如何插入list;如果是DFS,就把新得到的结点插入到
iterator的后面;如果是BFS,则把新的结点插入到list的后端;当iterator到达list的
末端时,则表示搜索结束。
为方便起见,我把DFS和BFS以及各种查重算法集中到一个.hpp文件,源码如下:
--------------------------------------------------------------------------------
*/
// Filename: bfs.h
#ifndef _BFS_DFS_HPP
#define _BFS_DFS_HPP
#pragma warning ( disable : 4786 )
#include <list>
#include <vector>
#include <set>
//#include <ext/hash_set>
//#include <hash_set>
using std::list;
using std::vector;
using std::set;
//using __gnu_cxx::hash_set;
//using __gnu_cxx::hash;
// 仿函式,用于不检查状态结点是否重复,搜索算法的两参数版本使用
// duplicate
template <class T>
struct NoCheckDup : std::unary_function<T, bool>
{
bool operator() (const T&) const
{
return false;
}
};
/*
// 仿函式,用hash_set容器检查状态结点是否重复
// 要求状态类提供operator==以及hash函数
template <class T, class HashFcn = hash<T> >
class HashCheckDup : std::unary_function<T, bool>
{
typedef hash_set<T, HashFcn> Cont;
Cont states_;
public:
typedef typename Cont::hasher hasher;
HashCheckDup(const hasher& hf) : states_(100, hf) {}
bool operator() (const T& s)
{
if (states_.find(s) != states_.end()) // 状态已存在,重复
{
return true;
}
states_.insert(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;
}
};
// 仿函式,用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;
}
};
template <class T1, class T2 >
int BreadthFirstSearch(const T1& initState, const T2& afterFindSolution)
// 两参数版本
// initState : 初始化状态,类T1应提供成员函数nextStep()和isTarget(),
// nextStep()用vector<T1>返回下一步可能的所有状态,
// isTarget()用于判断当前状态是否符合要求的答案;
// afterFindSolution : 仿函式,在找到一个有效答案后调用之,它接受一个const T1&,
// 并返回一个Boolean值,true表示停止搜索,false表示继续找
// return : 找到的答案数量
{
NoCheckDup<T1> noCheckDup;
return BreadthFirstSearch(initState, afterFindSolution, noCheckDup);
}
template <class T1, class T2, class T3 >
int BreadthFirstSearch(const T1& initState, const T2& afterFindSolution,
T3& checkDup)
// 三参数版本,前两个参数参考两参数版本说明
// checkDup : 仿函式,对于每一个下一步可能的状态调用之,它接受一个const T1&,
// 并返回一个Boolean值,true表示状态重复,false表示状态不重复
// checkDup的缺省值是不进行检查,假定所有生成的状态均不会重复
// return : 找到的答案数量
{
int n = 0;
list<T1> states;
states.push_back(initState);
typename list<T1>::iterator head = states.begin(); // 指向下个搜索的结点
vector<T1> nextStates;
bool stop = false;
while (!stop && head != states.end())
{
T1 s = *head; // 搜索一个结点
nextStates.clear();
s.nextStep(nextStates); // 从搜索点生成下一层结点
for (typename vector<T1>::iterator i = nextStates.begin();
i != nextStates.end(); ++i)
{
if (i->isTarget()) // 找到一个目标状态
{
++n;
if (stop = afterFindSolution(*i)) // 处理结果并决定是否停止
{
break;
}
}
else // 不是目标状态,判断是否放入搜索队列中
{
if (!checkDup(*i)) // 只将不重复的状态放入搜索队列
{
states.push_back(*i);
}
}
}
++head; // 指针移到下一个元素
}
return n;
}
template <class T1, class T2 >
int DepthFirstSearch(const T1& initState, const T2& afterFindSolution)
// 两参数版本
// initState : 初始化状态,类T1应提供成员函数nextStep()和isTarget(),
// nextStep()用vector<T1>返回下一步可能的所有状态,
// isTarget()用于判断当前状态是否符合要求的答案;
// afterFindSolution : 仿函式,在找到一个有效答案后调用之,它接受一个const T1&,
// 并返回一个Boolean值,true表示停止搜索,false表示继续找
// return : 找到的答案数量
{
NoCheckDup<T1> noCheckDup;
return DepthFirstSearch(initState, afterFindSolution, noCheckDup);
}
template <class T1, class T2, class T3 >
int DepthFirstSearch(const T1& initState, const T2& afterFindSolution,
T3& checkDup)
// 三参数版本,前两个参数参考两参数版本说明
// checkDup : 仿函式,对于每一个下一步可能的状态调用之,它接受一个const T1&,
// 并返回一个Boolean值,true表示状态重复,false表示状态不重复
// checkDup的缺省值是不进行检查,假定所有生成的状态均不会重复
// return : 找到的答案数量
{
int n = 0;
list<T1> states;
states.push_back(initState);
typename list<T1>::iterator head = states.begin(); // 指向下个搜索的结点
vector<T1> nextStates;
bool stop = false;
while (!stop && head != states.end())
{
T1 s = *head;
nextStates.clear();
s.nextStep(nextStates);
for (typename vector<T1>::iterator i = nextStates.begin();
i != nextStates.end(); ++i)
{
if (i->isTarget()) // 找到一个目标状态
{
++n;
if (stop = afterFindSolution(*i)) // 处理结果并决定是否停止
{
break;
}
}
else // 不是目标状态,判断是否放入搜索队列中
{
if (!checkDup(*i)) // 只将不重复的状态放入搜索队列
{
typename list<T1>::iterator it = head;
states.insert(++it, *i); // 插入到head的后面
}
}
}
++head;
}
return n;
}
#endif
//--------------------------------------------------------------------------------
//源代码要使用GCC编译,其中使用了STL的扩展容器hash_set,如果使用其它编译环境,则需要修改相应的头文件和容器名字空间。
//本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/alai04/archive/2006/06/03/771432.aspx