graph/example/knights_tour.cpp
Jeremy Siek 8590ee9b64 added traversal_category
[SVN r9672]
2001-03-29 02:04:10 +00:00

427 lines
12 KiB
C++

//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// This file is part of the Boost Graph Library
//
// You should have received a copy of the License Agreement for the
// Boost Graph Library along with the software; see the file LICENSE.
// If not, contact Office of Research, University of Notre Dame, Notre
// Dame, IN 46556.
//
// Permission to modify the code and to distribute modified code is
// granted, provided the text of this NOTICE is retained, a notice that
// the code was modified is included with the above COPYRIGHT NOTICE and
// with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
// file is distributed with the modified code.
//
// LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
// By way of example, but not limitation, Licensor MAKES NO
// REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
// PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
// OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
// OR OTHER RIGHTS.
//=======================================================================
#include <boost/config.hpp>
#include <stdlib.h>
#include <iostream>
#include <stack>
#include <queue>
#include <boost/operators.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/property_map.hpp>
typedef std::pair<int,int> Position;
static 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)
: pos(p), m_g(&g), i(ii) { valid_position(); }
Position operator*() const { return pos + knight_jumps[i]; }
void operator++() { ++i; valid_position(); }
bool operator==(const knight_adjacency_iterator& x) const
{ return i == x.i; }
protected:
void valid_position();
Position pos;
const knights_tour_graph* m_g;
int 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 boost::directed_tag directed_category;
typedef boost::disallow_parallel_edge_tag edge_parallel_category;
typedef boost::adjacency_graph_tag traversal_category;
knights_tour_graph(int n)
: m_board_size(n) { }
int m_board_size;
};
void knight_adjacency_iterator::valid_position()
{
Position new_pos = pos + knight_jumps[i];
while (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)) {
++i;
new_pos = pos + knight_jumps[i];
}
}
int num_vertices(const knights_tour_graph& g) { return g.m_board_size; }
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));
}
template <class Vertex, class Graph, class Board>
int number_of_successors(Vertex x, Graph g, Board board) {
int s_x = 0;
typename boost::graph_traits<Graph>::adjacency_iterator i, end;
for (boost::tie(i, end) = adjacent_vertices(x, g); i != end; ++i)
if (get(board, *i) == -1)
++s_x;
return s_x;
}
struct compare_first {
template <class P>
bool operator()(const P& x, const P& y) { return x.first < y.first; }
};
template <class Graph, class TimePropertyMap>
bool backtracking_search
(Graph& g,
typename boost::graph_traits<Graph>::vertex_descriptor x,
TimePropertyMap time_pa)
{
typedef typename boost::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, x));
while (!S.empty()) {
boost::tie(time_stamp, x) = S.top();
put(time_pa, x, time_stamp);
if (time_stamp == num_vertices(g) * num_vertices(g) - 1)
return true; // success!
bool deadend = true;
typename boost::graph_traits<Graph>::adjacency_iterator i, end;
for (boost::tie(i, end) = adjacent_vertices(x, g); i != end; ++i)
if (get(time_pa, *i) == -1) {
S.push(std::make_pair(time_stamp + 1, *i));
deadend = false;
}
if (deadend) {
put(time_pa, x, -1);
S.pop();
boost::tie(time_stamp, x) = S.top();
// unwind stack to unexplored vertex
while (get(time_pa, x) != -1) {
put(time_pa, x, -1);
S.pop();
boost::tie(time_stamp, x) = S.top();
}
}
} // while (!S.empty())
return false;
}
template <class Graph, class TimePropertyMap>
bool warnsdorff
(Graph& g,
typename boost::graph_traits<Graph>::vertex_descriptor src,
TimePropertyMap time_pa)
{
typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
typedef std::pair<int, Vertex> P;
std::stack<P> S;
std::priority_queue<P, std::vector<P>, compare_first> Q;
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_pa, x, time_stamp);
S.pop();
if (time_stamp == num_vertices(g) * num_vertices(g) - 1)
return true; // success!
typename boost::graph_traits<Graph>::adjacency_iterator i, end;
boost::tie(i, end) = adjacent_vertices(x, g);
int num_succ;
for (; i != end; ++i)
if (get(time_pa, *i) == -1) {
num_succ = number_of_successors(*i, g, time_pa);
Q.push(std::make_pair(num_succ, *i));
}
if (Q.empty()) { // hit dead-end
put(time_pa, x, -1);
boost::tie(time_stamp, x) = S.top();
while (get(time_pa, x) != -1) { // unwind stack
put(time_pa, x, -1);
S.pop();
boost::tie(time_stamp, x) = S.top();
}
} else {
for (; !Q.empty(); Q.pop()) {
boost::tie(num_succ, x) = Q.top();
S.push(std::make_pair(time_stamp + 1, x));
}
}
} // while (!S.empty())
return false;
}
struct board_map {
typedef int value_type;
typedef Position key_type;
typedef boost::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) * num_vertices(g)];
board_map chessboard(board, num_vertices(g));
for (int i = 0; i < num_vertices(g); ++i)
for (int j = 0; j < num_vertices(g); ++j)
put(chessboard, Position(i,j), -1);
bool ret = warnsdorff(g, Position(0,0), chessboard);
if (ret)
for (int i = 0; i < num_vertices(g); ++i) {
for (int j = 0; j < num_vertices(g); ++j)
std::cout << get(chessboard, Position(i,j)) << "\t";
std::cout << std::endl;
}
else
std::cout << "method failed" << std::endl;
return 0;
}
/*
(* Improved Warnsdorff's Algorithm for the Problem of *)
(* the Knight *)
(* Mathematica 2.2 Version Copyright 1992-93 Arnd Roth *)
knightJumps = {{2, -1}, {1, -2}, {-1, -2}, {-2, -1},
{-2, 1}, {-1, 2}, {1, 2 }, {2, 1 }};
successors[s_, n_, position_] :=
Block[{moves, onBoard},
moves = Map[position + # &, knightJumps];
(* moves over the edge of the chessboard are *)
(* invalid *)
onBoard = Select[moves, And @@ Thread[
{0, 0} < # <= {n, n}] &];
Select[onBoard, s[[Sequence @@ #]] == 0 &]
]
numberOfSuccessors[s_, n_, position_] :=
Length[successors[s, n, position]]
mina[s_, n_, position_] :=
(* successor(s) with least number of successors *)
Block[{localSuccessors, localNumbersOfSuccessors,
minimum},
localSuccessors = successors[s, n, position];
localNumbersOfSuccessors =
Map[numberOfSuccessors[s, n, #] &,
localSuccessors];
minimum = Min[localNumbersOfSuccessors];
localSuccessors[[Flatten[Positionition[
localNumbersOfSuccessors, minimum]]]]
]
mabst[destination_, successorlist_] :=
(* successor(s) with greatest distance from *)
(* destination *)
Block[{vectors, distances, maximum},
vectors = Map[destination - # &, successorlist];
distances = Map[# . # &, vectors];
maximum = Max[distances];
successorlist[[Flatten[Positionition[
distances, maximum]]]]
]
improvedWarnsdorff[n_] :=
(* main program *)
Block[{s, destination, position, localMina},
(* initialize chessboard s *)
(* s[[x, y]] == 0 ==> square (x, y) is *)
(* untouched. *)
(* in the end, s contains the step numbers *)
(* at which every square was visited *)
s = Table[0, {n}, {n}];
(* path should end near the following *)
destination =
{Round[n / 2] - 1 / 2, Round[n / 2] - 1 / 2};
(* starting point in the corner of the board *)
position = {1, 1};
s[[1, 1]] = 1;
Do[
localMina = mina[s, n, position];
If[Length[localMina] == 0,
Print["Blind alley"];
(* algorithm failed *)
Break[]
];
position = If[Length[localMina] == 1,
First[localMina],
First[mabst[destination,
localMina]]
];
s[[First[position], Last[position]]] =
stepNumber,
{stepNumber, 2, n n}];
s
] s
*/
#if 0
template <class Vertex, class Graph, class Board>
bool recursive_backtracking(Vertex x, Graph& g, Board chessboard, int t)
{
put(chessboard, x, t);
if (t == num_vertices(g) * num_vertices(g) - 1)
return true; // success!
typename boost::graph_traits<Graph>::adjacency_iterator i, end;
boost::tie(i, end) = adjacent_vertices(x, g);
for (; i != end; ++i)
if (get(chessboard, *i) == -1
&& recursive_backtracking(*i, g, chessboard, t + 1))
return true;
put(chessboard, x, -1);
return false;
}
template <class Graph, class Board>
bool backtracking(Graph& g, Board chessboard)
{
Position x(0,0);
int t = 0;
return recursive_backtracking(x, g, chessboard, t);
}
template <class Vertex, class Graph, class Board>
bool recursive_warnsdorff(Vertex u, Graph& g, Board chessboard, int t)
{
typename boost::graph_traits<Graph>::adjacency_iterator i, end;
typedef std::pair<int,Vertex> P;
std::priority_queue<P, std::vector<P>, compare_first> Q;
int num_succ;
put(chessboard, u, t);
if (t == num_vertices(g) * num_vertices(g) - 1)
return true; // success!
for (boost::tie(i, end) = adjacent_vertices(u, g); i != end; ++i)
if (get(chessboard, *i) == -1) {
num_succ = number_of_successors(*i, g, chessboard);
Q.push(std::make_pair(num_succ, *i));
}
for (; !Q.empty(); Q.pop()) {
Vertex v;
boost::tie(num_succ, v) = Q.top();
if (recursive_warnsdorff(v, g, chessboard, t + 1))
return true;
}
put(chessboard, u, -1);
return false;
}
template <class Graph, class Board>
bool warnsdorff(Graph& g, Board chessboard)
{
Position start(0,0);
int t = 0;
return recursive_warnsdorff(start, g, chessboard, t);
}
#endif