我已实施Dijkstra's algorithm。 但是当输入如下时它不起作用:
1
6 7
1 2 5
2 3 2
3 4 3
1 4 9
4 5 2
5 6 3
1 6 2
1
我在调试模式下运行它,以了解错误。似乎节点5没有插入单元中。我无法找出原因。
这里是代码:
#include<iostream>
#include<vector>
#include<list>
#include <limits>
#include <algorithm>
#include <queue>
#include <set>
#include <stack>
using namespace std;
struct compare
{
bool operator()(pair<int, int> a, pair<int, int> b) const
{
return a.second < b.second;
}
};
void printResults(vector<int> vec, int starting)
{
for (int i = 1; i < vec.size(); i++)
{
if (vec[i] == numeric_limits<int>::max() && i != starting)
{
cout << -1 << " ";
}
else if (i != starting)
{
cout << vec[i] << " ";
}
}
}
void djkstra(vector<vector<pair<int, int>>>&vec, int starting, int number_of_vertices)
{
int max = numeric_limits<int>::max();
set <pair<int, int>,compare> queue;
vector<bool> visited(number_of_vertices + 1, false);
vector<int> distances(number_of_vertices + 1, max);
vector<int> parents(number_of_vertices + 1, -1);
queue.insert(make_pair(starting, 0));
distances[starting] = 0;
for (int i = 0; i<number_of_vertices-1; i++)
{
pair<int, int> minElem = *queue.begin(); //take min elem
queue.erase(minElem);
vector<pair<int, int>> adjacents = vec[minElem.first];//take neighbours
for (int j = 0; j<adjacents.size(); j++)
{
pair<int, int> node = adjacents[j];
if (!visited[node.first])
{
if (distances[node.first]> distances[minElem.first] + node.second) //if we have found smaller distance
{
if (queue.find(make_pair(node.first, distances[node.first])) != queue.end())
{
queue.erase(make_pair(node.first, distances[node.first]));
queue.insert(make_pair(node.first, distances[minElem.first] + node.second));
}
else
{
queue.insert(make_pair(node.first, distances[minElem.first] + node.second));
cout<<distances[minElem.first] + node.second<<endl;
}
distances[node.first] = distances[minElem.first] + node.second;
}
}
}
visited[minElem.first] = true;
}
printResults(distances,starting);
}
int main()
{
int test;
cin >> test;
for (int i = 0; i < test; i++)
{
int nodes, edges;
cin >> nodes >> edges;
vector<vector<pair<int, int>>> vec(nodes + 1);
for (int j = 0; j < edges; j++)
{
int src, des, weight;
cin >> src >> des >> weight;
vec[src].push_back(make_pair(des, weight));
vec[des].push_back(make_pair(src, weight));
}
int starting;
cin >> starting;
djkstra(vec, starting, nodes);
}
system("pause");
return 0;
}
答案 0 :(得分:2)
所以,这是你的图表:
您的计划的输出是 Live On Coliru :
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_utility.hpp>
#include <iostream>
using Graph = boost::adjacency_list<
boost::vecS, boost::vecS, boost::directedS,
boost::no_property,
boost::property<boost::edge_weight_t, int>
>;
int main() {
std::cin.exceptions(std::ios::failbit);
int test; std::cin >> test;
for (int i = 0; i < test; i++) try {
int nodes, edges;
std::cin >> nodes >> edges;
std::cout << "Nodes:" << nodes << " Edges:" << edges << "\n";
Graph g(nodes + 1);
for (int j = 0; j < edges; j++) {
int src, des, weight;
std::cin >> src >> des >> weight;
std::cout << "src:" << src << " des:" << des << " weight:" << weight << "\n";
add_edge(src, des, weight, g);
}
boost::print_graph(g);
int starting;
std::cin >> starting;
std::vector<int> dist(num_vertices(g));
auto id = get(boost::vertex_index, g);
dijkstra_shortest_paths(g, starting,
weight_map(get(boost::edge_weight, g))
.distance_map(make_iterator_property_map(dist.begin(), id))
);
std::cout << "Distances:\n";
for (Graph::vertex_descriptor v = 0; v < num_vertices(g); v++) {
std::cout << starting << " -> " << v << " = " << dist[v] << "\n";
}
} catch(std::exception const& e) {
std::cout << "Error: " << e.what() << "\n";
}
}
打印:
Nodes:6 Edges:7
src:1 des:2 weight:5
src:2 des:3 weight:2
src:3 des:4 weight:3
src:1 des:4 weight:9
src:4 des:5 weight:2
src:5 des:6 weight:3
src:1 des:6 weight:2
0 -->
1 --> 2 4 6
2 --> 3
3 --> 4
4 --> 5
5 --> 6
6 -->
Distances:
1 -> 0 = 2147483647
1 -> 1 = 0
1 -> 2 = 5
1 -> 3 = 7
1 -> 4 = 9
1 -> 5 = 11
1 -> 6 = 2
这是对的!
这里是算法的输出,通过所有可到达的目标顶点设置动画:
正确的距离实际上应该是不言而喻的:
1: 0
2: 5
3: 5+2 = 7
4: 9 (5+2+3 is larger)
5: 9+2 = 11
6: 2 (both 5+2+3+2+3 and 9+2+3 are way larger)
是的,如果它是无向的,the outcome is different:
答案 1 :(得分:2)
所以,after尝试to让sense of成为question code,我根据the Wikipedia Pseudo-code
进行了干净的重写我想(因为你仍然没有显示出你认为错误的输出),你的基本错误只是使用set<>
:
<强> Bugged Version 强>
#include <algorithm>
#include <iostream>
#include <limits>
#include <list>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <cassert>
using Vertex = unsigned;
using Weight = double;
struct OutEdge {
Vertex node;
Weight weight;
bool operator<(OutEdge const& o) const { return weight < o.weight; }
};
using OutEdges = std::vector<OutEdge>;
using AdjList = std::vector<OutEdges>;
using Distances = std::vector<Weight>;
using Predecessors = std::vector<Vertex>;
static Weight const INFINITY = std::numeric_limits<Weight>::max();
static Vertex const UNDEFINED {-1u};
using namespace std;
void print_graph(AdjList const& graph) {
for (Vertex v = 1; v < graph.size(); v++) {
std::cout << v << " -";
for (auto& adj : graph[v])
std::cout << " " << adj.node << "(" << adj.weight << ")";
std::cout << "\n";
}
}
void printResults(Distances const& dist, Vertex starting) {
for (Vertex v = 0; v < dist.size(); v++) {
std::cout << starting << " -> " << v << ": ";
if (dist[v] == INFINITY && v != starting) {
cout << -1 << " ";
} else { // if (v != starting) {
cout << dist[v] << " ";
}
std::cout << "\n";
}
}
Distances dijkstra(AdjList const& graph, Vertex source) {
std::set<OutEdge> Q;
vector<bool> visited(graph.size(), false);
Distances dist(graph.size(), INFINITY); // Unkown distance from source
Predecessors prev(graph.size(), UNDEFINED); // Previous node in optimal path from source
dist[source] = 0; // Distance from source to source
for (Vertex v = 1; v < graph.size(); v++)
Q.insert({v, dist[v]});
while (!Q.empty()) {
Vertex u = Q.begin()->node;
visited[u] = true;
Q.erase(Q.begin());
for (auto& v : graph[u]) { // for each neighbour
if (visited[v.node]) // where v is still in Q.
continue;
Weight alt = dist[u] + v.weight;
if (alt < dist[v.node]) // A short path to v has been found
{
dist[v.node] = alt;
prev[v.node] = u;
// update prio
auto it = std::find_if(Q.begin(), Q.end(), [&](auto& oe) { return oe.node == v.node; });
if (it != Q.end()) {
Q.erase(it);
Q.insert({v.node, alt});
}
}
}
}
return dist;
}
int main() {
size_t test;
cin >> test;
for (size_t i = 0; i < test; i++) {
size_t nodes, edges;
cin >> nodes >> edges;
nodes += 1; // hack to avoid converting ids to base-0
AdjList adj(nodes);
for (size_t j = 0; j < edges; j++) {
Vertex src, des;
Weight weight;
cin >> src >> des >> weight;
assert(weight>=0);
adj[src].push_back({des, weight});
adj[des].push_back({src, weight});
}
print_graph(adj);
Vertex starting;
cin >> starting;
auto d = dijkstra(adj, starting);
printResults(d, starting);
}
}
将结果打印为:
1 -> 0: -1
1 -> 1: 0
1 -> 2: 5
1 -> 3: 7
1 -> 4: 9
1 -> 5: -1
1 -> 6: 2
注意 您在
djkstra
[原文如此]中至少还有一个错误for (int i = 0; i<number_of_vertices-1; i++)
-1
似乎是完全错误的(如果有的话,它应该“{应该”+1
,尽管有+1
遍布所有代码的代码气味很大。看看我在我的版本中如何解决这个问题。
std::set<>
为具有唯一元素的容器建模。在这种情况下,重量是等价性质,因此,具有相同重量的所有元素是等同的。在一开始,队列将包含最多2个元素:1个起始顶点(距离0)和1个其他顶点,这些顶点都以相同的距离播种(INFINITY
;或max
版本)。
由于许多节点从未被访问过(因为队列为空时算法就会停止),因此这会使您的算法下沉。
修正为5个字母:s/set/multiset/
:
<强> Fixed Version 强>
打印:
1 -> 0: -1
1 -> 1: 0
1 -> 2: 5
1 -> 3: 7
1 -> 4: 7
1 -> 5: 5
1 -> 6: 2