00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "base/hash.h"
00015 #include <vector>
00016
00017 #include "base/callback.h"
00018 #include "base/integral_types.h"
00019 #include "base/scoped_ptr.h"
00020 #include "base/adjustable_priority_queue.h"
00021
00022
00023 namespace operations_research {
00024 namespace {
00025
00026
00027 class Element {
00028 public:
00029 Element() : heap_index_(-1), distance_(0), node_(-1) {}
00030 bool operator <(const Element& other) const {
00031 return distance_ > other.distance_;
00032 }
00033 void SetHeapIndex(int h) { heap_index_ = h; }
00034 int GetHeapIndex() const { return heap_index_; }
00035 void set_distance(int64 distance) { distance_ = distance; }
00036 int64 distance() const { return distance_; }
00037 void set_node(int node) { node_ = node; }
00038 int node() const { return node_; }
00039 private:
00040 int heap_index_;
00041 int64 distance_;
00042 int node_;
00043 };
00044 }
00045
00046 class DijkstraSP {
00047 public:
00048 static const int64 kInfinity = kint64max / 2;
00049
00050 DijkstraSP(int node_count,
00051 int start_node,
00052 ResultCallback2<int64, int, int>* const graph,
00053 int64 disconnected_distance)
00054 : node_count_(node_count),
00055 start_node_(start_node),
00056 graph_(graph),
00057 disconnected_distance_(disconnected_distance),
00058 predecessor_(new int[node_count]),
00059 elements_(node_count) {
00060 graph->CheckIsRepeatable();
00061 }
00062 bool ShortestPath(int end_node, std::vector<int>* nodes);
00063 private:
00064 void Initialize();
00065 int SelectClosestNode(int64* distance);
00066 void Update(int label);
00067 void FindPath(int dest, std::vector<int>* nodes);
00068
00069 const int node_count_;
00070 const int start_node_;
00071 scoped_ptr<ResultCallback2<int64, int, int> > graph_;
00072 const int64 disconnected_distance_;
00073 scoped_array<int> predecessor_;
00074 AdjustablePriorityQueue<Element> frontier_;
00075 std::vector<Element> elements_;
00076 hash_set<int> not_visited_;
00077 hash_set<int> added_to_the_frontier_;
00078 };
00079
00080 void DijkstraSP::Initialize() {
00081 for (int i = 0; i < node_count_; i++) {
00082 elements_[i].set_node(i);
00083 if (i == start_node_) {
00084 predecessor_[i] = -1;
00085 elements_[i].set_distance(0);
00086 frontier_.Add(&elements_[i]);
00087 } else {
00088 elements_[i].set_distance(kInfinity);
00089 predecessor_[i] = start_node_;
00090 not_visited_.insert(i);
00091 }
00092 }
00093 }
00094
00095 int DijkstraSP::SelectClosestNode(int64* distance) {
00096 const int node = frontier_.Top()->node();
00097 *distance = frontier_.Top()->distance();
00098 frontier_.Pop();
00099 not_visited_.erase(node);
00100 added_to_the_frontier_.erase(node);
00101 return node;
00102 }
00103
00104 void DijkstraSP::Update(int node) {
00105 for (hash_set<int>::const_iterator it = not_visited_.begin();
00106 it != not_visited_.end();
00107 ++it) {
00108 const int other_node = *it;
00109 const int64 graph_node_i = graph_->Run(node, other_node);
00110 if (graph_node_i != disconnected_distance_) {
00111 if (added_to_the_frontier_.find(other_node) ==
00112 added_to_the_frontier_.end()) {
00113 frontier_.Add(&elements_[other_node]);
00114 added_to_the_frontier_.insert(other_node);
00115 }
00116 const int64 other_distance = elements_[node].distance() + graph_node_i;
00117 if (elements_[other_node].distance() > other_distance) {
00118 elements_[other_node].set_distance(other_distance);
00119 frontier_.NoteChangedPriority(&elements_[other_node]);
00120 predecessor_[other_node] = node;
00121 }
00122 }
00123 }
00124 }
00125
00126 void DijkstraSP::FindPath(int dest, std::vector<int>* nodes) {
00127 int j = dest;
00128 nodes->push_back(j);
00129 while (predecessor_[j] != -1) {
00130 nodes->push_back(predecessor_[j]);
00131 j = predecessor_[j];
00132 }
00133 }
00134
00135 bool DijkstraSP::ShortestPath(int end_node, std::vector<int>* nodes) {
00136 Initialize();
00137 bool found = false;
00138 while (!frontier_.IsEmpty()) {
00139 int64 distance;
00140 int node = SelectClosestNode(&distance);
00141 if (distance == kInfinity) {
00142 found = false;
00143 break;
00144 } else if (node == end_node) {
00145 found = true;
00146 break;
00147 }
00148 Update(node);
00149 }
00150 if (found) {
00151 FindPath(end_node, nodes);
00152 }
00153 return found;
00154 }
00155
00156 bool DijkstraShortestPath(int node_count,
00157 int start_node,
00158 int end_node,
00159 ResultCallback2<int64, int, int>* const graph,
00160 int64 disconnected_distance,
00161 std::vector<int>* nodes) {
00162 DijkstraSP bf(node_count, start_node, graph, disconnected_distance);
00163 return bf.ShortestPath(end_node, nodes);
00164 }
00165 }