一、Floyd算法
首先是Floyd算法,这种算法思路是最简单的,但是相对于来说,时间复杂度就高一些,这种方法核心思想就是不断进行边松弛优化,主要代码如下;
void Floyd(vector<vector<int>> &adjucent, int n) { //adjucent是邻接矩阵,n是点个数
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < n; ++k) {
if (adjucent[j][k] > adjucent[j][i] + adjucent[i][k])
adjucent[j][k] = adjucent[j][i] + adjucent[i][k];
}
}
}
}
时间复杂为O(n^3),这种方法适合多源最短路径,如果对时间复杂度有要求,可以参考dijkstra算法
二、Dijkstra算法
Dijktra算法,时间复杂度为O(n^2),依靠邻接矩阵,单源最短路径算法,但是这里未进行优化
#define INF INT_MAX
//adjucent为邻接矩阵、n为点个数、begin为起点,dist保存begin到各个点的最短路径,visit记录是否访问
void Dijkstra(vector<vector<int>> &adjucent, int n, int begin, int dist[],int visit[]) {
for (int i = 0; i < n; ++i) {
dist[i] = adjucent[begin][i];
}
visit[begin] = 1;
for (int i = 0; i < n; ++i) {
int min = INF, index = 0;
for (int j=0; j < n; ++j) {
if (visit[j] == 0 && dist[j] < min) { //找出每一个最小点,进行边松弛优化
min = dist[j];
index = j;
}
}
if (min != INF) {
visit[index] = 1;
for (int j = 0; j < n; ++j) {
if (adjucent[index][j] + adjucent[begin][index] <dist[j]) //边松弛优化
dist[j] = adjucent[index][j] + adjucent[begin][index];
}
}
}
}
可以看见,上述在寻找每一次的最小点的时候,都会浪费更多时间去寻找,因此可以利用堆进行优化,使得时间复杂度为O(nlogn),为了方便,这里直接采用了STL里面的优先队列priority_queue,如果不了解的,可以去参考《STL源码剖析》,采用堆优化,此时就不能依靠邻接矩阵了,可以依靠邻接表,因此总的代码如下:
#define INF INT_MAX
struct node {
int value;
int point;
node(int x,int y):point(x),value(y){}
bool operator < (const node &a) const { //因为采用了堆,因此必须重载<运算符建立对应堆
if (value == a.value) return point < a.point;
else
return value > a.value;
}
};
void Dijkstra_heap(vector<node> edge[],int n,int begin,int dist[]) {
priority_queue<node> q;
for (int i = 0; i < n; ++i) {
dist[i] = INF;
}
dist[begin] = 0;
q.push(node(begin, dist[begin]));
while (!q.empty()) {
node Q = q.top();
q.pop();
for (int i = 0; i < edge[Q.point].size(); ++i) {
node y = edge[Q.point][i];
if (dist[y.point] > y.value + Q.value)
{
dist[y.point] = y.value + Q.value;
q.push(node(y.point, dist[y.point]));
}
}
}
}
三、Bellman-Floyd算法
以上两种办法,都是解决非负权的图,如果出现负值的时候,以上两种办法就不合适了,主要考虑到负权值环的存在,因此需要采用Bellman-Floyd算法,该算法主要还是利用了边松弛,只是,当进行一次遍历后,需要判断是否存在负权值环,如果存在就不可能出现最小值,因此核心代码如下:
//prev[]用来保存寻找路径,dist[]保存最短路径权值,
struct edge
{
int u, v;
int val;
};
bool bellman_ford(edge e[], int pre[], int n, int m, int dist[]) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (dist[e[j].v] > dist[e[j].u] + e[j].val) {
dist[e[j].v] = dist[e[j].u] + e[j].val;
pre[e[j].v] = e[j].u;
}
}
}
int flag = 1;
for (int j = 0; j < m; ++j) {
if (dist[e[j].v] > dist[e[j].u] + e[j].val) {
flag = 0;
break;
}
}
return flag;
}