//======================================================================= // Copyright 2001 Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee, // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #include #include #include #include #include #include #include #include #include #include using namespace boost; typedef std::pair < int, int > Position; Position knight_jumps[8] = { Position(2, -1), Position(1, -2), Position(-1, -2), Position(-2, -1), Position(-2, 1), Position(-1, 2), Position(1, 2), Position(2, 1) }; Position operator + (const Position & p1, const Position & p2) { return Position(p1.first + p2.first, p1.second + p2.second); } struct knights_tour_graph; struct knight_adjacency_iterator: public boost::forward_iterator_helper < knight_adjacency_iterator, Position, std::ptrdiff_t, Position *, Position > { knight_adjacency_iterator() { } knight_adjacency_iterator(int ii, Position p, const knights_tour_graph & g) : m_pos(p), m_g(&g), m_i(ii) { valid_position(); } Position operator *() const { return m_pos + knight_jumps[m_i]; } void operator++ () { ++m_i; valid_position(); } bool operator == (const knight_adjacency_iterator & x) const { return m_i == x. m_i; } protected: void valid_position(); Position m_pos; const knights_tour_graph * m_g; int m_i; }; struct knights_tour_graph { typedef Position vertex_descriptor; typedef std::pair < vertex_descriptor, vertex_descriptor > edge_descriptor; typedef knight_adjacency_iterator adjacency_iterator; typedef void out_edge_iterator; typedef void in_edge_iterator; typedef void edge_iterator; typedef void vertex_iterator; typedef int degree_size_type; typedef int vertices_size_type; typedef int edges_size_type; typedef directed_tag directed_category; typedef disallow_parallel_edge_tag edge_parallel_category; typedef adjacency_graph_tag traversal_category; knights_tour_graph(int n): m_board_size(n) { } int m_board_size; }; int num_vertices(const knights_tour_graph & g) { return g.m_board_size * g.m_board_size; } void knight_adjacency_iterator::valid_position() { Position new_pos = m_pos + knight_jumps[m_i]; while (m_i < 8 && (new_pos.first < 0 || new_pos.second < 0 || new_pos.first >= m_g->m_board_size || new_pos.second >= m_g->m_board_size)) { ++m_i; new_pos = m_pos + knight_jumps[m_i]; } } std::pair < knights_tour_graph::adjacency_iterator, knights_tour_graph::adjacency_iterator > adjacent_vertices(knights_tour_graph::vertex_descriptor v, const knights_tour_graph & g) { typedef knights_tour_graph::adjacency_iterator Iter; return std::make_pair(Iter(0, v, g), Iter(8, v, g)); } struct compare_first { template < typename P > bool operator() (const P & x, const P & y) { return x.first < y.first; } }; template < typename Graph, typename TimePropertyMap > bool backtracking_search(Graph & g, typename graph_traits < Graph >::vertex_descriptor src, TimePropertyMap time_map) { typedef typename graph_traits < Graph >::vertex_descriptor Vertex; typedef std::pair < int, Vertex > P; std::stack < P > S; int time_stamp = 0; S.push(std::make_pair(time_stamp, src)); while (!S.empty()) { Vertex x; boost::tie(time_stamp, x) = S.top(); put(time_map, x, time_stamp); // all vertices have been visited, success! if (time_stamp == num_vertices(g) - 1) return true; bool deadend = true; typename graph_traits < Graph >::adjacency_iterator i, end; for (boost::tie(i, end) = adjacent_vertices(x, g); i != end; ++i) if (get(time_map, *i) == -1) { S.push(std::make_pair(time_stamp + 1, *i)); deadend = false; } if (deadend) { put(time_map, x, -1); S.pop(); boost::tie(time_stamp, x) = S.top(); while (get(time_map, x) != -1) { // unwind stack to last unexplored vertex put(time_map, x, -1); S.pop(); boost::tie(time_stamp, x) = S.top(); } } } // while (!S.empty()) return false; } template < typename Vertex, typename Graph, typename TimePropertyMap > int number_of_successors(Vertex x, Graph & g, TimePropertyMap time_map) { int s_x = 0; typename graph_traits < Graph >::adjacency_iterator i, end; for (boost::tie(i, end) = adjacent_vertices(x, g); i != end; ++i) if (get(time_map, *i) == -1) ++s_x; return s_x; } template < typename Graph, typename TimePropertyMap > bool warnsdorff(Graph & g, typename graph_traits < Graph >::vertex_descriptor src, TimePropertyMap time_map) { typedef typename graph_traits < Graph >::vertex_descriptor Vertex; typedef std::pair < int, Vertex > P; std::stack < P > S; int time_stamp = 0; S.push(std::make_pair(time_stamp, src)); while (!S.empty()) { Vertex x; boost::tie(time_stamp, x) = S.top(); put(time_map, x, time_stamp); // all vertices have been visited, success! if (time_stamp == num_vertices(g) - 1) return true; // Put adjacent vertices into a local priority queue std::priority_queue < P, std::vector < P >, compare_first > Q; typename graph_traits < Graph >::adjacency_iterator i, end; int num_succ; for (boost::tie(i, end) = adjacent_vertices(x, g); i != end; ++i) if (get(time_map, *i) == -1) { num_succ = number_of_successors(*i, g, time_map); Q.push(std::make_pair(num_succ, *i)); } bool deadend = Q.empty(); // move vertices from local priority queue to the stack for (; !Q.empty(); Q.pop()) { boost::tie(num_succ, x) = Q.top(); S.push(std::make_pair(time_stamp + 1, x)); } if (deadend) { put(time_map, x, -1); S.pop(); boost::tie(time_stamp, x) = S.top(); while (get(time_map, x) != -1) { // unwind stack to last unexplored vertex put(time_map, x, -1); S.pop(); boost::tie(time_stamp, x) = S.top(); } } } // while (!S.empty()) return false; } struct board_map { typedef int value_type; typedef Position key_type; typedef read_write_property_map_tag category; board_map(int *b, int n):m_board(b), m_size(n) { } friend int get(const board_map & ba, Position p); friend void put(const board_map & ba, Position p, int v); friend std::ostream & operator << (std::ostream & os, const board_map & ba); private: int *m_board; int m_size; }; int get(const board_map & ba, Position p) { return ba.m_board[p.first * ba.m_size + p.second]; } void put(const board_map & ba, Position p, int v) { ba.m_board[p.first * ba.m_size + p.second] = v; } std::ostream & operator << (std::ostream & os, const board_map & ba) { for (int i = 0; i < ba.m_size; ++i) { for (int j = 0; j < ba.m_size; ++j) os << get(ba, Position(i, j)) << "\t"; os << std::endl; } return os; } int main(int argc, char *argv[]) { int N; if (argc == 2) N = atoi(argv[1]); else N = 8; knights_tour_graph g(N); int * board = new int[num_vertices(g)]; board_map chessboard(board, N); for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) put(chessboard, Position(i, j), -1); bool ret = warnsdorff(g, Position(0, 0), chessboard); if (ret) for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) std::cout << get(chessboard, Position(i, j)) << "\t"; std::cout << std::endl; } else std::cout << "method failed" << std::endl; return 0; }