您的位置:首页 > 编程语言

趣味编程:用BGL求解八数码问题(A*)

2010-04-24 01:43 471 查看
A* Graph Search Within the BGL Framework

代码

#include <algorithm>
#include <iostream>
#include <list>

#include "nonconst_bfs.hpp" // so we can modify the graph
#include <boost/graph/astar_search.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/bimap.hpp>
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
using namespace boost;
using namespace std;

class pstate_t : public vector<int>
{
public:
	int m_r, m_c;
	optional<char> m_dir;
	pstate_t() {}
	pstate_t(int rows, int cols)
		: vector<int>(m_r * m_c), m_r(rows), m_c(cols) {}
	template <class I>
	pstate_t(int rows, int cols, I beg, I end)
		: vector<int>(beg, end), m_r(rows), m_c(cols) {}
	inline int get(int r, int c) const {
		return operator[](cell(r, c));
	}
	inline void move(int i, int j, char dir) {
		int tmp = operator[](i);
		operator[](i) = operator[](j);
		operator[](j) = tmp;
		m_dir = dir;
	}
	// find offset of coordinates
	inline int cell(int r, int c) const {
		return r * m_c + c;
	}
	// find coordinates of an offset
	inline void coords(int i, int &r, int &c) const {
		r = i / m_c;
		c = i % m_c;
	}
};
ostream & operator<<(ostream &out, const pstate_t &p)
{
	if(p.m_dir)
		out << "move: " << *p.m_dir << endl;
	for(int i = 0; i < p.m_r; ++i) {
		for(int j = 0; j < p.m_c; ++j) {
			if(p.get(i, j) > 0)
				out << p.get(i, j) << " ";
			else
				out << "  ";
		}
		out << endl;
	}
	return out;
}

void gen_children(const pstate_t &p, list<pstate_t> &children)
{
	pstate_t::const_iterator i = find(p.begin(), p.end(), 0);
	int sr, sc, soff = i - p.begin();
	p.coords(soff, sr, sc);
	if(sc > 0) { // move tile to left of space
		children.push_back(p);
		children.back().move(soff, p.cell(sr, sc - 1), 'w');
	}
	if(sc < p.m_c - 1) { // move tile to right of space
		children.push_back(p);
		children.back().move(soff, p.cell(sr, sc + 1), 'e');
	}
	if(sr > 0) { // move tile above space
		children.push_back(p);
		children.back().move(soff, p.cell(sr - 1, sc), 'n');
	}
	if(sr < p.m_r - 1) { // move tile below space
		children.push_back(p);
		children.back().move(soff, p.cell(sr + 1, sc), 's');
	}
}

typedef property<vertex_color_t, default_color_type,
	property<vertex_rank_t, unsigned int,
	property<vertex_distance_t, unsigned int,
	property<vertex_predecessor_t, unsigned int> > > > vert_prop;
typedef property<edge_weight_t, unsigned int> edge_prop;
typedef adjacency_list<listS, vecS, undirectedS, vert_prop, edge_prop> mygraph_t;
typedef mygraph_t::vertex_descriptor vertex_t;
typedef mygraph_t::vertex_iterator vertex_iterator_t;
typedef bimap<vertex_t, pstate_t> StateMap;
typedef property_map<mygraph_t, edge_weight_t>::type WeightMap;
typedef property_map<mygraph_t, vertex_predecessor_t>::type PredMap;
typedef property_map<mygraph_t, vertex_distance_t>::type DistMap;

struct found_goal {};
template <class VisitorType>
class puz_visitor : public VisitorType
{
public:
	puz_visitor(pstate_t &goal, list<vertex_t> &seq, StateMap &smap)
		: m_goal(goal), m_seq(seq), m_smap(smap) {}
	template <class Vertex, class Graph>
	void examine_vertex(Vertex u, Graph& g) {
		m_seq.push_back(u);
		VisitorType::examine_vertex(u, g);
		DistMap dmap = get(vertex_distance_t(), g);
		// check for goal
		const pstate_t& cur = m_smap.left.at(u);
		if(cur == m_goal)
			throw found_goal();
		// add successors of this state
		list<pstate_t> children;
		gen_children(cur, children);
		BOOST_FOREACH(pstate_t& child, children) {
			// make sure this state is new
			try{
				vertex_t v = m_smap.right.at(child);
				//add_edge(u, v, edge_prop(1), g);
			} catch(out_of_range&) {
				vertex_t v = add_vertex(vert_prop(white_color), g);
				m_smap.insert(StateMap::relation(v, child));
				dmap[v] = numeric_limits<unsigned int>::max();
				add_edge(u, v, edge_prop(1), g);
			}
		}
	}
private:
	pstate_t &m_goal;
	list<vertex_t> &m_seq;
	StateMap &m_smap;
};

// manhattan distance heuristic
class manhattan_dist
	: public astar_heuristic<mygraph_t, unsigned int>
{
public:
	manhattan_dist(pstate_t &goal, StateMap &smap)
		: m_goal(goal), m_smap(smap) {}
	unsigned int operator()(vertex_t u) {
		unsigned int md = 0;
		pstate_t::const_iterator i, j;
		int ir, ic, jr, jc;
		const pstate_t& cur = m_smap.left.at(u);
		for(i = cur.begin(); i != cur.end(); ++i) {
			j = find(m_goal.begin(), m_goal.end(), *i);
			cur.coords(i - cur.begin(), ir, ic);
			m_goal.coords(j - m_goal.begin(), jr, jc);
			md += myabs(jr - ir) + myabs(jc - ic);
		}
		return md;
	}
private:
	pstate_t &m_goal;
	StateMap &m_smap;
	inline unsigned int myabs(int i) {
		return static_cast<unsigned int>(i < 0 ? -i : i);
	}
};

int main(int argc, char **argv)
{
	mygraph_t g;
	list<vertex_t> examine_seq;
	StateMap smap;
	vertex_t start = add_vertex(vert_prop(white_color), g);
	//int sstart[] = {2, 8, 3, 1, 6, 4, 7, 0, 5}; // 5 steps
	//int sstart[] = {2, 1, 6, 4, 0, 8, 7, 5, 3}; // 18 steps
	//int sgoal[] = {1, 2, 3, 8, 0, 4, 7, 6, 5};
	int sstart[] = {7, 5, 6, 8, 3, 2, 4, 0, 1}; // 23 steps
	int sgoal[] = {1, 2, 3, 4, 5, 6, 7, 8, 0};
	smap.insert(StateMap::relation(start, pstate_t(3, 3, &sstart[0], &sstart[9])));
	pstate_t psgoal(3, 3, &sgoal[0], &sgoal[9]);
	cout << "Start state:" << endl << smap.left.at(start) << endl;
	cout << "Goal state:" << endl << psgoal << endl;
	try {
		puz_visitor<default_astar_visitor> vis(psgoal, examine_seq, smap);
		astar_search(g, start, manhattan_dist(psgoal, smap),
			visitor(vis).color_map(get(vertex_color, g)).
			rank_map(get(vertex_rank, g)).
			distance_map(get(vertex_distance, g)).
			predecessor_map(get(vertex_predecessor, g)));
	} catch(found_goal&) {
		PredMap p = get(vertex_predecessor, g);
		list<vertex_t> shortest_path;
		for(vertex_t v = examine_seq.back();; v = p[v]) {
			shortest_path.push_front(v);
			if(p[v] == v)
				break;
		}
		cout << "Sequence of moves:" << endl;
		BOOST_FOREACH(vertex_t v, shortest_path)
			cout << smap.left.at(v) << endl;
		cout << "Number of moves: "
			<< shortest_path.size() - 1 << endl;
		cout << "Number of vertices examined: "
			<< examine_seq.size() << endl;
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: