图论最短路径问题
图论中的图(Graph)是由若干给定的点及连接两点的线所构成的图形,通常用来事物之间的特定关系。一个图可以用数学语言描述为 $G(V(G),E(G))$。V(vertex) 指的是图的顶点集,E(edge) 指的是图的边集。
根据边是否有方向,可将图分为有向图和无向图,有些图的边上有权重值,这样的图成为有权图。
Dijkstra 算法
具体 C++ 代码:
// Calculate The Shortest Distance Between The Starting And The Ending Node
int calculate(int start, int end) {
vector<bool> visited(nodeCnt + 1);
vector<int> d(nodeCnt + 1);
vector<int> waiting;
int curr = start;
// Initialize
for(int i = 1; i <= nodeCnt; i++) {
d[i] = 0;
visited[i] = 0;
}
while(curr != end) {
Node* currNode = graph[curr];
visited[curr] = true;
for(int i = 0; i < currNode->ptr.size(); i++) {
if(visited[currNode->ptr[i]->id] == false) {
printf("从节点 %d 到 %d 距离 %d\n", curr, currNode->ptr[i]->id, currNode->distance[i]);
if(d[currNode->ptr[i]->id] == 0) {
waiting.push_back(currNode->ptr[i]->id);
d[currNode->ptr[i]->id] = d[curr] + currNode->distance[i];
} else {
d[currNode->ptr[i]->id] = min(d[currNode->ptr[i]->id], d[curr] + currNode->distance[i]);
}
}
}
printf("=====================Information====================");
printf("\nid : ");
for(int i = 1; i < d.size(); i++) printf("%3d ", i);
printf("\ndistance: ");
for(int i = 1; i < d.size(); i++) printf("%3d ", d[i]);
printf("\nvisited : ");
for(int i = 1; i < d.size(); i++) printf("%3d ", visited[i] ? 1 : 0);
printf("\n====================================================\n");
printf("Waiting Queue: ");
for(int i = 0; i < waiting.size(); i++) printf("%3d", waiting[i]);
printf("\n");
if(waiting.size() == 0) return -1;
vector<int>::iterator itor;
vector<int>::iterator target = waiting.begin();
for(itor = waiting.begin(); itor != waiting.end(); itor++) {
if(d[*itor] < d[*target] && visited[*itor] == false) target = itor;
}
curr = *target;
waiting.erase(target);
}
return d[end];
}
完整代码到文末,代码并没有为节点的父节点进行记录,有需要可自行添加。
Matlab 中求最短路径
[P, d] = shortestpath(G, start, end [, 'Method', algorithm]);
G为输入图,start和end分别是起点和终点,Method和algorithm是可选的参数,分别代表最短路径的算法,一般不用特别设置。返回值 P 和 d 分别是最短路径经过的节点以及其最短距离。
Matlab 中返回任意两点的距离矩阵
d = distances(G [,'Method', algorithm]);
返回一个 NxN 的矩阵,代表点 i 到点 j 的距离。
Matlab 中返回给定范围内的所有点
[nodeIDs, dist] = nearest(G, s, d [, 'Method', algorithm]);
nodeIDs 就是范围内的节点的 ID,dist 就是距离。
Dijkstra 算法完整代码部分
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
#include<unordered_map>
using namespace std;
class Node {
public:
int id;
vector<Node *> ptr;
vector<int> distance;
Node(int id) : id(id) {}
};
class Graph{
private:
int nodeCnt = 0;
unordered_map<int, Node *> graph;
public:
// Insert A Node To Graph
bool insert(int id) {
if(graph.find(id) != graph.end()) return false;
graph[id] = new Node(id);
nodeCnt = max(id, nodeCnt);
return true;
}
// Connect Two Nodes On The Graph
bool connect(int node1, int node2, int distance, bool oneWay = true) {
if(graph.find(node1) == graph.end()) return false;
if(graph.find(node2) == graph.end()) return false;
graph[node1]->ptr.push_back(graph[node2]);
graph[node1]->distance.push_back(distance);
if(oneWay) return true;
graph[node2]->ptr.push_back(graph[node1]);
graph[node2]->distance.push_back(distance);
return true;
}
// Calculate The Shortest Distance Between The Starting And The Ending Node
int calculate(int start, int end) {
vector<bool> visited(nodeCnt + 1);
vector<int> d(nodeCnt + 1);
vector<int> waiting;
int curr = start;
// Initialize
for(int i = 1; i <= nodeCnt; i++) {
d[i] = 0;
visited[i] = 0;
}
while(curr != end) {
Node* currNode = graph[curr];
visited[curr] = true;
for(int i = 0; i < currNode->ptr.size(); i++) {
if(visited[currNode->ptr[i]->id] == false) {
printf("从节点 %d 到 %d 距离 %d\n", curr, currNode->ptr[i]->id, currNode->distance[i]);
if(d[currNode->ptr[i]->id] == 0) {
waiting.push_back(currNode->ptr[i]->id);
d[currNode->ptr[i]->id] = d[curr] + currNode->distance[i];
} else {
d[currNode->ptr[i]->id] = min(d[currNode->ptr[i]->id], d[curr] + currNode->distance[i]);
}
}
}
printf("=====================Information====================");
printf("\nid : ");
for(int i = 1; i < d.size(); i++) printf("%3d ", i);
printf("\ndistance: ");
for(int i = 1; i < d.size(); i++) printf("%3d ", d[i]);
printf("\nvisited : ");
for(int i = 1; i < d.size(); i++) printf("%3d ", visited[i] ? 1 : 0);
printf("\n====================================================\n");
printf("Waiting Queue: ");
for(int i = 0; i < waiting.size(); i++) printf("%3d", waiting[i]);
printf("\n");
if(waiting.size() == 0) return -1;
vector<int>::iterator itor;
vector<int>::iterator target = waiting.begin();
for(itor = waiting.begin(); itor != waiting.end(); itor++) {
if(d[*itor] < d[*target] && visited[*itor] == false) target = itor;
}
curr = *target;
waiting.erase(target);
}
return d[end];
}
};
int main() {
Graph* g = new Graph();
char c = 'w';
int node1, node2, distance, oneWay;
scanf("%c", &c);
while(c != 'e') {
switch(c) {
case 'i':
scanf("%d", &node1);
if(g->insert(node1)) {
printf("插入节点 %d 成功\n", node1);
} else {
printf("插入节点 %d 失败\n", node1);
}
break;
case 'c':
scanf("%d %d %d %d", &node1, &node2, &distance, &oneWay);
if(g->connect(node1, node2, distance, (oneWay) ? true : false)) {
printf("连接节点 %d 到 %d 成功,距离 %d,方向 %s\n", node1, node2, distance, (oneWay) ? "单向" : "双向");
} else {
printf("连接节点 %d 到 %d 失败。\n", node1, node2);
}
break;
case 'd':
scanf("%d %d", &node1, &node2);
printf("节点 %d 到 %d 的距离为(-1为无法到达):%d\n", node1, node2, g->calculate(node1, node2));
break;
}
scanf("%c", &c);
}
return 0;
}
版权属于:江筱雨
本文链接:https://www.yuisblog.com/archives/209/
本站未注明转载的文章均为原创,并采用
CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!