d51ba76e20
Fix C++17 build errors in examples. Disable some examples that use Unix-ism's from building on other platforms.
344 lines
8.0 KiB
C++
344 lines
8.0 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;
|
|
}
|