AimRT/_deps/boost-src/libs/graph/example/knights_tour.cpp
2025-01-12 20:40:08 +08:00

287 lines
8.3 KiB
C++

//=======================================================================
// 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 <boost/config.hpp>
#include <stdlib.h>
#include <iostream>
#include <stack>
#include <queue>
#include <ctime>
#include <boost/operators.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/property_map/property_map.hpp>
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;
}