mirror of
https://github.com/boostorg/graph.git
synced 2025-05-11 13:24:01 +00:00
427 lines
12 KiB
C++
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
|