Add shortest paths algorithms (Bellman-Ford and Dijkstra)
This commit is contained in:
23
Makefile
23
Makefile
@@ -39,7 +39,13 @@ BINARIES=nqueens golomb magic_square cryptarithm
|
||||
|
||||
all: libs $(BINARIES) pylib
|
||||
|
||||
libs: libcp.a libutil.a libbase.a libalgorithms.a libgraph.a
|
||||
libs: \
|
||||
libcp.a \
|
||||
libutil.a \
|
||||
libbase.a \
|
||||
libalgorithms.a \
|
||||
libgraph.a \
|
||||
libshortestpaths.a
|
||||
|
||||
clean:
|
||||
rm -f *.a
|
||||
@@ -149,6 +155,21 @@ objs/bron_kerbosch.o:graph/bron_kerbosch.cc
|
||||
libgraph.a: $(GRAPH_LIB_OBJS)
|
||||
ar rv libgraph.a $(GRAPH_LIB_OBJS)
|
||||
|
||||
# Shortestpaths library.
|
||||
|
||||
SHORTESTPATHS_LIB_OBJS=\
|
||||
objs/bellman_ford.o \
|
||||
objs/dijkstra.o
|
||||
|
||||
objs/bellman_ford.o:graph/bellman_ford.cc
|
||||
$(CCC) $(CFLAGS) -c graph/bellman_ford.cc -o objs/bellman_ford.o
|
||||
|
||||
objs/dijkstra.o:graph/dijkstra.cc
|
||||
$(CCC) $(CFLAGS) -c graph/dijkstra.cc -o objs/dijkstra.o
|
||||
|
||||
libshortestpaths.a: $(SHORTESTPATHS_LIB_OBJS)
|
||||
ar rv libshortestpaths.a $(SHORTESTPATHS_LIB_OBJS)
|
||||
|
||||
# Algorithms library.
|
||||
|
||||
ALGORITHMS_LIB_OBJS=\
|
||||
|
||||
24
Makefile.msv
24
Makefile.msv
@@ -24,7 +24,14 @@ BINARIES=nqueens.exe golomb.exe magic_square.exe cryptarithm.exe
|
||||
|
||||
all: libs $(BINARIES)
|
||||
|
||||
LIBS = cp.lib util.lib base.lib gflags.lib algorithms.lib graph.lib
|
||||
LIBS = \
|
||||
cp.lib \
|
||||
util.lib \
|
||||
base.lib \
|
||||
gflags.lib \
|
||||
algorithms.lib \
|
||||
graph.lib \
|
||||
shortestpaths.lib
|
||||
|
||||
libs: $(LIBS)
|
||||
|
||||
@@ -135,6 +142,21 @@ objs/bron_kerbosch.obj:graph/bron_kerbosch.cc
|
||||
graph.lib: $(GRAPH_LIB_OBJS)
|
||||
lib /OUT:graph.lib $(GRAPH_LIB_OBJS)
|
||||
|
||||
# Shortestpaths library.
|
||||
|
||||
SHORTESTPATHS_LIB_OBJS=\
|
||||
objs/bellman_ford.obj \
|
||||
objs/dijkstra.obj
|
||||
|
||||
objs/bellman_ford.o:graph/bellman_ford.cc
|
||||
$(CCC) $(CFLAGS) -c graph/bellman_ford.cc /Foobjs/bellman_ford.obj
|
||||
|
||||
objs/dijkstra.o:graph/dijkstra.cc
|
||||
$(CCC) $(CFLAGS) -c graph/dijkstra.cc /Foobjs/dijkstra.obj
|
||||
|
||||
libshortestpaths.a: $(SHORTESTPATHS_LIB_OBJS)
|
||||
lib /OUT:shortestpaths.lib $(SHORTESTPATHS_LIB_OBJS)
|
||||
|
||||
# Algorithms library.
|
||||
|
||||
ALGORITHMS_LIB_OBJS=\
|
||||
|
||||
134
base/adjustable_priority_queue.h
Normal file
134
base/adjustable_priority_queue.h
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright 2010 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
|
||||
#ifndef BASE_ADJUSTABLE_PRIORITY_QUEUE_H
|
||||
#define BASE_ADJUSTABLE_PRIORITY_QUEUE_H
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
template<typename T> class AdjustablePriorityQueue {
|
||||
public:
|
||||
|
||||
AdjustablePriorityQueue() {}
|
||||
|
||||
void Add(T* const val) {
|
||||
elems_.push_back(val);
|
||||
AdjustUpwards(elems_.size() - 1);
|
||||
}
|
||||
|
||||
void Remove(T* const val) {
|
||||
int i = val->GetHeapIndex();
|
||||
if (i == Size() - 1) {
|
||||
elems_.resize(Size()-1);
|
||||
return;
|
||||
}
|
||||
elems_[i] = elems_.back();
|
||||
elems_[i]->SetHeapIndex(i);
|
||||
elems_.pop_back();
|
||||
NoteChangedPriority(elems_[i]);
|
||||
}
|
||||
|
||||
bool Contains(const T* const val) const {
|
||||
const int i = val->GetHeapIndex();
|
||||
if (i < 0 || i >= elems_.size() || elems_[i] != val) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NoteChangedPriority(T* val) {
|
||||
const int i = val->GetHeapIndex();
|
||||
const int parent = (i - 1) / 2;
|
||||
if (*elems_[parent] < *val) {
|
||||
AdjustUpwards(i);
|
||||
} else {
|
||||
AdjustDownwards(i);
|
||||
}
|
||||
}
|
||||
|
||||
T* Top() { return elems_[0]; }
|
||||
|
||||
const T* Top() const { return elems_[0]; }
|
||||
|
||||
void Pop() { Remove(Top()); }
|
||||
|
||||
int Size() const { return elems_.size(); }
|
||||
|
||||
bool IsEmpty() const { return elems_.size() == 0; }
|
||||
|
||||
void Clear() { elems_.resize(0); }
|
||||
|
||||
void CheckValid() const {
|
||||
for (int i = 0; i < Size(); ++i) {
|
||||
int left_child = 1 + 2 * i;
|
||||
if (left_child < Size()) {
|
||||
CHECK_GE(elems_[i], elems_[left_child]);
|
||||
}
|
||||
int right_child = left_child + 1;
|
||||
if (right_child < Size()) {
|
||||
CHECK_GE(elems_[i], elems_[right_child]);
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
void AdjustUpwards(int i) {
|
||||
T* const t = elems_[i];
|
||||
while (i > 0) {
|
||||
const int parent = (i - 1) / 2;
|
||||
if (!(*elems_[parent] < *t)) {
|
||||
break;
|
||||
}
|
||||
elems_[i] = elems_[parent];
|
||||
elems_[i]->SetHeapIndex(i);
|
||||
i = parent;
|
||||
}
|
||||
elems_[i] = t;
|
||||
t->SetHeapIndex(i);
|
||||
}
|
||||
|
||||
void AdjustDownwards(int i) {
|
||||
T* const t = elems_[i];
|
||||
while (true) {
|
||||
const int left_child = 1 + 2 * i;
|
||||
if (left_child >= elems_.size()) {
|
||||
break;
|
||||
}
|
||||
const int right_child = left_child + 1;
|
||||
const int next_i = (right_child < elems_.size() &&
|
||||
*elems_[left_child] < *elems_[right_child]) ?
|
||||
right_child :
|
||||
left_child;
|
||||
if (!(*t < *elems_[next_i])) {
|
||||
break;
|
||||
}
|
||||
elems_[i] = elems_[next_i];
|
||||
elems_[i]->SetHeapIndex(i);
|
||||
i = next_i;
|
||||
}
|
||||
elems_[i] = t;
|
||||
t->SetHeapIndex(i);
|
||||
}
|
||||
|
||||
vector<T*> elems_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AdjustablePriorityQueue);
|
||||
};
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // BASE_ADJUSTABLE_PRIORITY_QUEUE_H
|
||||
123
graph/bellman_ford.cc
Normal file
123
graph/bellman_ford.cc
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 2010 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/integral_types.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
|
||||
#include "graph/graph.h"
|
||||
|
||||
DECLARE_int32(shortestpaths_disconnected_distance);
|
||||
|
||||
namespace operations_research {
|
||||
class BellmanFord {
|
||||
public:
|
||||
static const int64 kInfinity = kint64max / 2;
|
||||
|
||||
BellmanFord(int node_count,
|
||||
int start_node,
|
||||
ResultCallback2<int64, int, int>* const graph)
|
||||
: node_count_(node_count),
|
||||
start_node_(start_node),
|
||||
graph_(graph),
|
||||
distance_(new int64[node_count_]),
|
||||
predecessor_(new int[node_count_]) {
|
||||
graph->CheckIsRepeatable();
|
||||
}
|
||||
bool ShortestPath(int end_node, vector<int>* nodes);
|
||||
private:
|
||||
void Initialize();
|
||||
void Update();
|
||||
bool Check() const;
|
||||
void FindPath(int dest, vector<int>* nodes) const;
|
||||
|
||||
const int node_count_;
|
||||
const int start_node_;
|
||||
scoped_ptr<ResultCallback2<int64, int, int> > graph_;
|
||||
scoped_array<int64> distance_;
|
||||
scoped_array<int> predecessor_;
|
||||
};
|
||||
|
||||
void BellmanFord::Initialize() {
|
||||
for (int i = 0; i < node_count_; i++) {
|
||||
distance_[i] = kint64max / 2;
|
||||
predecessor_[i] = -1;
|
||||
}
|
||||
distance_[start_node_] = 0;
|
||||
}
|
||||
|
||||
void BellmanFord::Update() {
|
||||
for (int i = 0; i < node_count_ - 1; i++) {
|
||||
for (int u = 0; u < node_count_; u++) {
|
||||
for (int v = 0; v < node_count_; v++) {
|
||||
const int64 graph_u_v = graph_->Run(u, v);
|
||||
if (graph_u_v != FLAGS_shortestpaths_disconnected_distance) {
|
||||
const int64 other_distance = distance_[u] + graph_u_v;
|
||||
if (distance_[v] > other_distance) {
|
||||
distance_[v] = other_distance;
|
||||
predecessor_[v] = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BellmanFord::Check() const {
|
||||
for (int u = 0; u < node_count_; u++) {
|
||||
for (int v = 0; v < node_count_; v++) {
|
||||
const int graph_u_v = graph_->Run(u, v);
|
||||
if (graph_u_v != FLAGS_shortestpaths_disconnected_distance) {
|
||||
if (distance_[v] > distance_[u] + graph_u_v) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BellmanFord::FindPath(int dest, vector<int>* nodes) const {
|
||||
int j = dest;
|
||||
nodes->push_back(j);
|
||||
while (predecessor_[j] != -1) {
|
||||
nodes->push_back(predecessor_[j]);
|
||||
j = predecessor_[j];
|
||||
}
|
||||
}
|
||||
|
||||
bool BellmanFord::ShortestPath(int end_node, vector<int>* nodes) {
|
||||
Initialize();
|
||||
Update();
|
||||
if (distance_[end_node] == kInfinity) {
|
||||
return false;
|
||||
}
|
||||
if (!Check()) {
|
||||
return false;
|
||||
}
|
||||
FindPath(end_node, nodes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BellmanFordShortestPath(int node_count,
|
||||
int start_node,
|
||||
int end_node,
|
||||
ResultCallback2<int64, int, int>* const graph,
|
||||
vector<int>* nodes) {
|
||||
BellmanFord bf(node_count, start_node, graph);
|
||||
return bf.ShortestPath(end_node, nodes);
|
||||
}
|
||||
} // namespace operations_research
|
||||
166
graph/dijkstra.cc
Normal file
166
graph/dijkstra.cc
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright 2010 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <hash_set>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/integral_types.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
|
||||
#include "graph/shortestpaths.h"
|
||||
#include "base/adjustable_priority_queue.h"
|
||||
|
||||
|
||||
DECLARE_int32(shortestpaths_disconnected_distance);
|
||||
|
||||
namespace operations_research {
|
||||
namespace {
|
||||
|
||||
// Priority queue element
|
||||
class Element {
|
||||
public:
|
||||
Element() : heap_index_(-1), distance_(0), node_(-1) {}
|
||||
bool operator <(const Element& other) const {
|
||||
return distance_ > other.distance_;
|
||||
}
|
||||
void SetHeapIndex(int h) { heap_index_ = h; }
|
||||
int GetHeapIndex() const { return heap_index_; }
|
||||
void set_distance(int64 distance) { distance_ = distance; }
|
||||
int64 distance() const { return distance_; }
|
||||
void set_node(int node) { node_ = node; }
|
||||
int node() const { return node_; }
|
||||
private:
|
||||
int heap_index_;
|
||||
int64 distance_;
|
||||
int node_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
class DijkstraSP {
|
||||
public:
|
||||
static const int64 kInfinity = kint64max / 2;
|
||||
|
||||
DijkstraSP(int node_count,
|
||||
int start_node,
|
||||
ResultCallback2<int64, int, int>* const graph)
|
||||
: node_count_(node_count),
|
||||
start_node_(start_node),
|
||||
graph_(graph),
|
||||
predecessor_(new int[node_count]),
|
||||
elements_(node_count) {
|
||||
graph->CheckIsRepeatable();
|
||||
}
|
||||
bool ShortestPath(int end_node, vector<int>* nodes);
|
||||
private:
|
||||
void Initialize();
|
||||
int SelectClosestNode(int64* distance);
|
||||
void Update(int label);
|
||||
void FindPath(int dest, vector<int>* nodes);
|
||||
|
||||
const int node_count_;
|
||||
const int start_node_;
|
||||
scoped_ptr<ResultCallback2<int64, int, int> > graph_;
|
||||
scoped_array<int> predecessor_;
|
||||
AdjustablePriorityQueue<Element> frontier_;
|
||||
vector<Element> elements_;
|
||||
hash_set<int> not_visited_;
|
||||
hash_set<int> added_to_the_frontier_;
|
||||
};
|
||||
|
||||
void DijkstraSP::Initialize() {
|
||||
for (int i = 0; i < node_count_; i++) {
|
||||
elements_[i].set_node(i);
|
||||
if (i == start_node_) {
|
||||
predecessor_[i] = -1;
|
||||
elements_[i].set_distance(0);
|
||||
frontier_.Add(&elements_[i]);
|
||||
} else {
|
||||
elements_[i].set_distance(kInfinity);
|
||||
predecessor_[i] = start_node_;
|
||||
not_visited_.insert(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DijkstraSP::SelectClosestNode(int64* distance) {
|
||||
const int node = frontier_.Top()->node();
|
||||
*distance = frontier_.Top()->distance();
|
||||
frontier_.Pop();
|
||||
not_visited_.erase(node);
|
||||
added_to_the_frontier_.erase(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
void DijkstraSP::Update(int node) {
|
||||
for (hash_set<int>::const_iterator it = not_visited_.begin();
|
||||
it != not_visited_.end();
|
||||
++it) {
|
||||
const int other_node = *it;
|
||||
const int64 graph_node_i = graph_->Run(node, other_node);
|
||||
if (graph_node_i != FLAGS_shortestpaths_disconnected_distance) {
|
||||
if (added_to_the_frontier_.find(other_node) ==
|
||||
added_to_the_frontier_.end()) {
|
||||
frontier_.Add(&elements_[other_node]);
|
||||
added_to_the_frontier_.insert(other_node);
|
||||
}
|
||||
const int64 other_distance = elements_[node].distance() + graph_node_i;
|
||||
if (elements_[other_node].distance() > other_distance) {
|
||||
elements_[other_node].set_distance(other_distance);
|
||||
frontier_.NoteChangedPriority(&elements_[other_node]);
|
||||
predecessor_[other_node] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DijkstraSP::FindPath(int dest, vector<int>* nodes) {
|
||||
int j = dest;
|
||||
nodes->push_back(j);
|
||||
while (predecessor_[j] != -1) {
|
||||
nodes->push_back(predecessor_[j]);
|
||||
j = predecessor_[j];
|
||||
}
|
||||
}
|
||||
|
||||
bool DijkstraSP::ShortestPath(int end_node, vector<int>* nodes) {
|
||||
Initialize();
|
||||
bool found = false;
|
||||
while (!frontier_.IsEmpty()) {
|
||||
int64 distance;
|
||||
int node = SelectClosestNode(&distance);
|
||||
if (distance == kInfinity) {
|
||||
found = false;
|
||||
break;
|
||||
} else if (node == end_node) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
Update(node);
|
||||
}
|
||||
if (found) {
|
||||
FindPath(end_node, nodes);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool DijkstraShortestPath(int node_count,
|
||||
int start_node,
|
||||
int end_node,
|
||||
ResultCallback2<int64, int, int>* const graph,
|
||||
vector<int>* nodes) {
|
||||
DijkstraSP bf(node_count, start_node, graph);
|
||||
return bf.ShortestPath(end_node, nodes);
|
||||
}
|
||||
} // namespace operations_research
|
||||
60
graph/shortestpaths.h
Normal file
60
graph/shortestpaths.h
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2010 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This file contains various shortestpaths utilities.
|
||||
|
||||
#ifndef GRAPH_SHORTESTPATHS_H_
|
||||
#define GRAPH_SHORTESTPATHS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback-types.h"
|
||||
#include "base/integral_types.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
|
||||
// Dijsktra Shortest path with callback based description of the graph.
|
||||
// The callback returns the distance between two nodes, a distance of
|
||||
// 'shortestpaths_disconnected_distance' (flag) indicates no arcs between these
|
||||
// two nodes. Ownership of the callback is taken by the function that will
|
||||
// delete it in the end.
|
||||
// This function returns true if 'start_node' and 'end_node' are connected,
|
||||
// false otherwise.
|
||||
bool DijkstraShortestPath(int node_count,
|
||||
int start_node,
|
||||
int end_node,
|
||||
ResultCallback2<int64, int, int>* const graph,
|
||||
vector<int>* nodes);
|
||||
|
||||
// Bellman-Ford Shortest path with callback-based description of the graph.
|
||||
// The callback returns the distance between two nodes, a distance of
|
||||
// 'shortestpaths_disconnected_distance' (flag) indicates no arcs between
|
||||
// these two nodes.
|
||||
// Ownership of the callback is taken by the function that will delete it
|
||||
// in the end.
|
||||
// This function returns true if 'start_node' and 'end_node' are connected,
|
||||
// false otherwise. If true, it will fill the 'nodes' vector with the
|
||||
// sequence of nodes on the shortest path between 'start_node' and 'end_node'.
|
||||
bool BellmanFordShortestPath(int node_count,
|
||||
int start_node,
|
||||
int end_node,
|
||||
ResultCallback2<int64, int, int>* const graph,
|
||||
vector<int>* nodes);
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // GRAPH_SHORTESTPATHS_H_
|
||||
Reference in New Issue
Block a user