参考:图论最短距离(Shortest Path)算法动画演示-Dijkstra(迪杰斯特拉)和Floyd(弗洛伊德)
问题的提法
- 已知一个各边权值均大于 0 的带权有向图,对每一对顶点 v
i
≠ vj
,求出 vi
与 vj
之间的最短路径值以及最短路径上的顶点。
Floyd 算法核心
定义一个 n 阶方阵序列:
- A-1, A0,..., An-1
其中:
- A-1[i][j] = Edge[i][j]
- Ak[i][j] = min{ Ak-1[i][j], Ak-1[i][k] + Ak-1[k][j]}
- k = 0, 1, ..., n-1
n 阶方阵中元素的意义
- A-1[i][j]: v
i
到 vj
的权值,无中间顶点- A0[i][j]: v
i
到 vj
的路径长度,路径的中间顶点为 0- A1[i][j]: v
i
到 vj
的路径长度, 路径的中间顶点可能为0或1- ......
- Ak[i][j]: v
i
到 vj
的路径长度, 路径的中间顶点编号不大于k- ......
- An-1[i][j]: v
i
到 vj
的最短路径长度
Floyd 算法实例
Floyd 算法精髓
A-1 定义为邻接矩阵,则:
- A0, ...,An-1 通过中转顶点逐一递推得到
Ak 矩阵中元素的更新
- Ak[i][j] = min{ Ak-1[i][j], Ak-1[i][k] + Ak-1[k][j] }
A 矩阵的推导就是最短路径的推导
- A[i][j] 为 i 到 j 的路径值,在推导过程中逐步减小
Floyd 算法的实现
初始化
本质: 使用邻接矩阵初始化 A-1
for(int i=0; i<vCount(); ++i)
{
for (int j=0; j<vCount(); ++j)
{
dist[i][j] = getEdge(i, j);
}
}
A0, ..., An-1 矩阵推导
本质:使用中转顶点逐步推导最短路径
for (int k=0; k<vCount; ++k)
{
for (int i=0; i<vCount(); ++i)
{
for (int j=0; j<vCount(); ++j)
{
if ((dist[i][k] + dist[k][j]) < dist[i][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
编程实验:最短路径算法
文件:Graph.h
#ifndef GRAPH_H
#define GRAPH_H
#include "Object.h"
#include "SharedPointer.h"
#include "DynamicArray.h"
#include "LinkQueue.h"
#include "LinkStack.h"
#include "Sort.h"
namespace DTLib
{
template <typename E>
struct Edge : public Object
{
int b;
int e;
E data;
Edge(int i=-1, int j=-1) : b(i), e(j)
{
}
Edge(int i, int j, const E &value) : b(i), e(j), data(value)
{
}
bool operator == (const Edge &obj)
{
return (b == obj.b) && (e == obj.e);
}
bool operator != (const Edge &obj)
{
return !(*this == obj);
}
bool operator < (const Edge &obj)
{
return (data < obj.data);
}
bool operator > (const Edge &obj)
{
return (data > obj.data);
}
};
template <typename V, typename E>
class Graph : public Object
{
public:
virtual V getVertex(int i) const = 0;
virtual bool getVertex(int i, V &value) const = 0;
virtual bool setVertex(int i, const V &value) = 0;
virtual SharedPointer<Array<int>> getAdjacent(int i) const = 0;
virtual bool isAdjacent(int i, int j) const = 0;
virtual E getEdge(int i, int j) const = 0;
virtual bool getEdge(int i, int j, E &value) const = 0;
virtual bool setEdge(int i, int j, const E &value) = 0;
virtual bool removeEdge(int i, int j) = 0;
virtual int vCount() const = 0;
virtual int eCount() = 0;
virtual int OD(int i) = 0;
virtual int ID(int i) = 0;
virtual int TD(int i)
{
return OD(i) + ID(i);
}
bool asUndirected()
{
bool ret = true;
for (int i=0; i<vCount() && ret; ++i)
{
for (int j=0; j<vCount() && ret; ++j)
{
if (isAdjacent(i, j))
{
ret = isAdjacent(j, i) && (getEdge(i, j) == getEdge(j, i));
}
}
}
return ret;
}
SharedPointer<Array<int>> BFS(int i)
{
DynamicArray<int> *ret = nullptr;
if ((0 <= i) && (i < vCount()))
{
LinkQueue<int> q;
LinkQueue<int> r;
DynamicArray<bool> visited(vCount());
for (int j=0; j<visited.length(); ++j)
{
visited[j] = false;
}
q.add(i);
while (q.length() > 0)
{
int v = q.front();
q.remove();
if (!visited[v])
{
SharedPointer<Array<int>> aj = getAdjacent(v);
for (int j=0; j<aj->length(); ++j)
{
q.add((*aj)[j]);
}
r.add(v);
visited[v] = true;
}
}
ret = toArray(r);
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ...");
}
return ret;
}
#ifdef DFS_R
SharedPointer<Array<int>> DFS(int i) // 递归版深度优先遍历
{
DynamicArray<int> *ret = nullptr;
if ((0 <= i) && (i < vCount()))
{
LinkQueue<int> r;
DynamicArray<bool> visited(vCount());
for (int j=0; j<vCount(); ++j)
{
visited[j] = false;
}
DFP(i, visited, r);
ret = toArray(r);
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ...");
}
return ret;
}
#else
SharedPointer<Array<int>> DFS(int i)
{
DynamicArray<int> *ret = nullptr;
if ((0 <= i) && (i < vCount()))
{
LinkStack<int> s;
LinkQueue<int> r;
DynamicArray<bool> visited(vCount());
for (int j=0; j<visited.length(); ++j)
{
visited[j] = false;
}
s.push(i);
while (s.size() > 0)
{
int v = s.top();
s.pop();
if (!visited[v])
{
SharedPointer<Array<int>> aj = getAdjacent(v);
for (int j=aj->length()-1; j>=0; --j)
{
s.push((*aj)[j]);
}
r.add(v);
visited[v] = true;
}
}
ret = toArray(r);
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ...");
}
return ret;
}
#endif
SharedPointer<Array<Edge<E>>> prim(const E &LIMIT, const bool MINIMUM = true)
{
LinkQueue<Edge<E>> ret;
if (asUndirected())
{
DynamicArray<int> adjVex(vCount());
DynamicArray<bool> mark(vCount());
DynamicArray<E> cost(vCount());
SharedPointer<Array<int>> aj = nullptr;
bool end = false;
int v = 0;
for (int i=0; i<vCount(); ++i)
{
adjVex[i] = -1;
mark[i] = false;
cost[i] = LIMIT;
}
mark[v] = true;
aj = getAdjacent(v);
for (int i=0; i<aj->length(); ++i)
{
cost[(*aj)[i]] = getEdge(v, (*aj)[i]);
adjVex[(*aj)[i]] = v;
}
for (int i=0; i<vCount() && !end; ++i)
{
E m = LIMIT;
int k = -1;
for (int j=0; j<vCount(); ++j)
{
if (!mark[j] && (MINIMUM ? (m > cost[j]) : (m < cost[j])))
{
m = cost[j];
k = j;
}
}
end = (k == -1);
if (!end)
{
ret.add(Edge<E>(adjVex[k],k, getEdge(adjVex[k],k)));
mark[k] = true;
aj = getAdjacent(k);
for (int j=0; j<aj->length(); ++j)
{
if (!mark[(*aj)[j]] && (MINIMUM ? (getEdge(k, (*aj)[j]) < cost[(*aj)[j]]) : (getEdge(k, (*aj)[j]) > cost[(*aj)[j]])))
{
cost[(*aj)[j]] = getEdge(k, (*aj)[j]);
adjVex[(*aj)[j]] = k;
}
}
}
}
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "Prim operator is for undirected grap only ...");
}
if (ret.length() != (vCount() - 1))
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No enough edge for prim operation ...");
}
return toArray(ret);
}
SharedPointer<Array<Edge<E>>> Kruskal( const bool MINIMUM = true)
{
LinkQueue<Edge<E>> ret;
DynamicArray<int> p(vCount());
SharedPointer<Array<Edge<E>>> edges = getUndirectedEdges();
for (int i=0; i<p.length(); ++i)
{
p[i] = -1;
}
Sort::Shell(*edges, MINIMUM);
for (int i=0; (i<edges->length()) && (ret.length() < (vCount()-1)); ++i)
{
int b = find(p, (*edges)[i].b);
int e = find(p, (*edges)[i].e);
if (b != e)
{
p[e] = b;
ret.add((*edges)[i]);
}
}
if (ret.length() != vCount() - 1)
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No enough edges for Kruskal operation ...");
}
return toArray(ret);
}
SharedPointer<Array<int>> dijkstra(int i, int j, const E &LIMIT)
{
LinkQueue<int> ret;
if ((0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount()))
{
DynamicArray<E> dist(vCount());
DynamicArray<int> path(vCount());
DynamicArray<bool> mark(vCount());
for (int k=0; k<vCount(); ++k)
{
mark[k] = false;
path[k] = -1;
dist[k] = isAdjacent(i, k) ? (path[k]=i, getEdge(i, k)) : LIMIT;
}
mark[i] = true;
for (int k=0; k<vCount(); ++k)
{
E m = LIMIT;
int u = -1;
for (int w=0; w<vCount(); ++w)
{
if (!mark[w] && dist[w] < m)
{
m = dist[w];
u = w;
}
}
if (u == -1)
{
break;
}
mark[u] = true;
for (int w=0; w<vCount(); ++w)
{
if (!mark[w] && isAdjacent(u, w) && (dist[u] + getEdge(u, w) < dist[w]))
{
dist[w] = dist[u] + getEdge(u, w);
path[w] = u;
}
}
}
LinkStack<int> s;
s.push(j);
for (int k=path[j]; k!=-1; k=path[k])
{
s.push(k);
}
while (s.size() > 0)
{
ret.add(s.top());
s.pop();
}
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "Parameter <i, j> is invalid ...");
}
if (ret.length() < 2)
{
THROW_EXCEPTION(ArithmeticExcption, "This is no path from i to j ...");
}
return toArray(ret);
}
int floyd(int x, int y, const E &LIMIT)
{
int ret = -1;
if ((0 <= x) && (x < vCount()) && (0 <= y) && (y < vCount()))
{
DynamicArray<DynamicArray<E>> dist(vCount());
for (int k=0; k<vCount(); ++k)
{
dist[k].resize(vCount());
}
for (int i=0; i<vCount(); ++i)
{
for (int j=0; j<vCount(); ++j)
{
dist[i][j] = isAdjacent(i, j) ? getEdge(i, j) : LIMIT;
}
}
for (int k=0; k<vCount(); ++k)
{
for (int i=0; i<vCount(); ++i)
{
for (int j=0; j<vCount(); ++j)
{
if (dist[i][j] > (dist[i][k] + dist[k][j]))
{
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
ret = dist[x][y];
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter <x, y> is invalid ...");
}
return ret;
}
protected:
template <typename T>
DynamicArray<T>* toArray(LinkQueue<T> &queue)
{
DynamicArray<T> *ret = new DynamicArray<T>(queue.length());
if (ret != nullptr)
{
for (int i=0; i<ret->length(); ++i, queue.remove())
{
ret->set(i, queue.front());
}
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create ret obj ...");
}
return ret;
}
#ifdef DFS_R
void DFP(int i, DynamicArray<bool> &visited, LinkQueue<int>& queue)
{
if (!visited[i])
{
queue.add(i);
visited[i] = true;
SharedPointer<Array<int>> aj = getAdjacent(i);
for (int j=0; j<aj->length(); ++j)
{
DFP((*aj)[j], visited, queue);
}
}
}
#endif
int find(Array<int> &p, int v)
{
while (p[v] != -1)
{
v = p[v];
}
return v;
}
SharedPointer<Array<Edge<E>>> getUndirectedEdges()
{
DynamicArray<Edge<E>> *ret = nullptr;
if (asUndirected())
{
LinkQueue<Edge<E>> queue;
for (int i=0; i<vCount(); ++i)
{
for (int j=0; j<vCount(); ++j)
{
if (isAdjacent(i, j))
{
queue.add(Edge<E>(i, j, getEdge(i, j)));
}
}
}
ret = toArray(queue);
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "This function is for undirected graph only ...");
}
return ret;
}
};
}
#endif // GRAPH_H
文件:main.cpp
#include <iostream>
#include "MatrixGraph.h"
#include "ListGraph.h"
using namespace std;
using namespace DTLib;
template< typename V, typename E >
Graph<V, E>& GraphEasy()
{
static MatrixGraph<4, V, E> g;
g.setEdge(0, 1, 1);
g.setEdge(0, 2, 3);
g.setEdge(1, 2, 1);
g.setEdge(1, 3, 4);
g.setEdge(2, 3, 1);
return g;
}
template< typename V, typename E >
Graph<V, E>& GraphComplex()
{
static ListGraph<V, E> g(5);
g.setEdge(0, 1, 10);
g.setEdge(0, 3, 30);
g.setEdge(0, 4, 100);
g.setEdge(1, 2, 50);
g.setEdge(2, 4, 10);
g.setEdge(3, 2, 20);
g.setEdge(3, 4, 60);
return g;
}
template< typename V, typename E >
Graph<V, E>& GraphSample()
{
static ListGraph<V, E> g(3);
g.setEdge(0, 1, 4);
g.setEdge(0, 2, 11);
g.setEdge(1, 2, 2);
g.setEdge(1, 0, 6);
g.setEdge(2, 0, 3);
return g;
}
int main()
{
Graph<int, int> &g = GraphSample<int, int>();
for (int i=0; i<g.vCount(); ++i)
{
for (int j=0; j<g.vCount(); ++j)
{
cout << g.floyd(i, j, 65535) << " ";
}
cout << endl;
}
return 0;
}
输出:
9 4 6
5 9 2
3 7 9
问题:如何记录最短路径上的各个顶点?
定义辅助矩阵
int path[N][N]; // 路径矩阵
- path[i][j] 表示 i 到 j 的路径上所经过的第 1 个顶点
初始化:
- path[i][j] = -1; <i, j> 无边直接连接时
- path[i][j] = j; <i, j> 有边直接连接时
修改:
if ((dist[i][k] + dist[k][j]) < dist[i][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
path[i][j] = path[i][k];
}
说明:
当已找到最短路径[0, 3]: 0 → 1 → 2 → 3,那么所经过的第一个顶点为 1;
也因此可得最短路径[0, 2]:0 → 1 → 2, 那么所经过的第一个顶点为1
因此:path[i][j] = path[i][k];
路径矩阵示例
初始:
dist[0][1] = 1; path[0][1] = 1;
dist[0][2] = 3; path[0][2] = 2;
dist[1][2] = 1; path[1][2] = 2
推导:
因为: dist[0][1] + dist[1][2] < dist[0][2]
所以: dist[0][2] = dist[0][1] + dist[1][2]
path[0][2] = path[0][1]
最短路径顶点推导
// x 起始顶点
// y 终止顶点
while ((x != -1) && (x != y))
{
ret.add(x);
x = path[x][y];
}
if (x != -1)
{
ret.add(x);
}
编程实验: Floyd 算法的改善
文件:Graph.h
#ifndef GRAPH_H
#define GRAPH_H
#include "Object.h"
#include "SharedPointer.h"
#include "DynamicArray.h"
#include "LinkQueue.h"
#include "LinkStack.h"
#include "Sort.h"
namespace DTLib
{
template <typename E>
struct Edge : public Object
{
int b;
int e;
E data;
Edge(int i=-1, int j=-1) : b(i), e(j)
{
}
Edge(int i, int j, const E &value) : b(i), e(j), data(value)
{
}
bool operator == (const Edge &obj)
{
return (b == obj.b) && (e == obj.e);
}
bool operator != (const Edge &obj)
{
return !(*this == obj);
}
bool operator < (const Edge &obj)
{
return (data < obj.data);
}
bool operator > (const Edge &obj)
{
return (data > obj.data);
}
};
template <typename V, typename E>
class Graph : public Object
{
public:
virtual V getVertex(int i) const = 0;
virtual bool getVertex(int i, V &value) const = 0;
virtual bool setVertex(int i, const V &value) = 0;
virtual SharedPointer<Array<int>> getAdjacent(int i) const = 0;
virtual bool isAdjacent(int i, int j) const = 0;
virtual E getEdge(int i, int j) const = 0;
virtual bool getEdge(int i, int j, E &value) const = 0;
virtual bool setEdge(int i, int j, const E &value) = 0;
virtual bool removeEdge(int i, int j) = 0;
virtual int vCount() const = 0;
virtual int eCount() = 0;
virtual int OD(int i) = 0;
virtual int ID(int i) = 0;
virtual int TD(int i)
{
return OD(i) + ID(i);
}
bool asUndirected()
{
bool ret = true;
for (int i=0; i<vCount() && ret; ++i)
{
for (int j=0; j<vCount() && ret; ++j)
{
if (isAdjacent(i, j))
{
ret = isAdjacent(j, i) && (getEdge(i, j) == getEdge(j, i));
}
}
}
return ret;
}
SharedPointer<Array<int>> BFS(int i)
{
DynamicArray<int> *ret = nullptr;
if ((0 <= i) && (i < vCount()))
{
LinkQueue<int> q;
LinkQueue<int> r;
DynamicArray<bool> visited(vCount());
for (int j=0; j<visited.length(); ++j)
{
visited[j] = false;
}
q.add(i);
while (q.length() > 0)
{
int v = q.front();
q.remove();
if (!visited[v])
{
SharedPointer<Array<int>> aj = getAdjacent(v);
for (int j=0; j<aj->length(); ++j)
{
q.add((*aj)[j]);
}
r.add(v);
visited[v] = true;
}
}
ret = toArray(r);
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ...");
}
return ret;
}
#ifdef DFS_R
SharedPointer<Array<int>> DFS(int i) // 递归版深度优先遍历
{
DynamicArray<int> *ret = nullptr;
if ((0 <= i) && (i < vCount()))
{
LinkQueue<int> r;
DynamicArray<bool> visited(vCount());
for (int j=0; j<vCount(); ++j)
{
visited[j] = false;
}
DFP(i, visited, r);
ret = toArray(r);
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ...");
}
return ret;
}
#else
SharedPointer<Array<int>> DFS(int i)
{
DynamicArray<int> *ret = nullptr;
if ((0 <= i) && (i < vCount()))
{
LinkStack<int> s;
LinkQueue<int> r;
DynamicArray<bool> visited(vCount());
for (int j=0; j<visited.length(); ++j)
{
visited[j] = false;
}
s.push(i);
while (s.size() > 0)
{
int v = s.top();
s.pop();
if (!visited[v])
{
SharedPointer<Array<int>> aj = getAdjacent(v);
for (int j=aj->length()-1; j>=0; --j)
{
s.push((*aj)[j]);
}
r.add(v);
visited[v] = true;
}
}
ret = toArray(r);
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter i is invalid ...");
}
return ret;
}
#endif
SharedPointer<Array<Edge<E>>> prim(const E &LIMIT, const bool MINIMUM = true)
{
LinkQueue<Edge<E>> ret;
if (asUndirected())
{
DynamicArray<int> adjVex(vCount());
DynamicArray<bool> mark(vCount());
DynamicArray<E> cost(vCount());
SharedPointer<Array<int>> aj = nullptr;
bool end = false;
int v = 0;
for (int i=0; i<vCount(); ++i)
{
adjVex[i] = -1;
mark[i] = false;
cost[i] = LIMIT;
}
mark[v] = true;
aj = getAdjacent(v);
for (int i=0; i<aj->length(); ++i)
{
cost[(*aj)[i]] = getEdge(v, (*aj)[i]);
adjVex[(*aj)[i]] = v;
}
for (int i=0; i<vCount() && !end; ++i)
{
E m = LIMIT;
int k = -1;
for (int j=0; j<vCount(); ++j)
{
if (!mark[j] && (MINIMUM ? (m > cost[j]) : (m < cost[j])))
{
m = cost[j];
k = j;
}
}
end = (k == -1);
if (!end)
{
ret.add(Edge<E>(adjVex[k],k, getEdge(adjVex[k],k)));
mark[k] = true;
aj = getAdjacent(k);
for (int j=0; j<aj->length(); ++j)
{
if (!mark[(*aj)[j]] && (MINIMUM ? (getEdge(k, (*aj)[j]) < cost[(*aj)[j]]) : (getEdge(k, (*aj)[j]) > cost[(*aj)[j]])))
{
cost[(*aj)[j]] = getEdge(k, (*aj)[j]);
adjVex[(*aj)[j]] = k;
}
}
}
}
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "Prim operator is for undirected grap only ...");
}
if (ret.length() != (vCount() - 1))
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No enough edge for prim operation ...");
}
return toArray(ret);
}
SharedPointer<Array<Edge<E>>> Kruskal( const bool MINIMUM = true)
{
LinkQueue<Edge<E>> ret;
DynamicArray<int> p(vCount());
SharedPointer<Array<Edge<E>>> edges = getUndirectedEdges();
for (int i=0; i<p.length(); ++i)
{
p[i] = -1;
}
Sort::Shell(*edges, MINIMUM);
for (int i=0; (i<edges->length()) && (ret.length() < (vCount()-1)); ++i)
{
int b = find(p, (*edges)[i].b);
int e = find(p, (*edges)[i].e);
if (b != e)
{
p[e] = b;
ret.add((*edges)[i]);
}
}
if (ret.length() != vCount() - 1)
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No enough edges for Kruskal operation ...");
}
return toArray(ret);
}
SharedPointer<Array<int>> dijkstra(int i, int j, const E &LIMIT)
{
LinkQueue<int> ret;
if ((0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount()))
{
DynamicArray<E> dist(vCount());
DynamicArray<int> path(vCount());
DynamicArray<bool> mark(vCount());
for (int k=0; k<vCount(); ++k)
{
mark[k] = false;
path[k] = -1;
dist[k] = isAdjacent(i, k) ? (path[k]=i, getEdge(i, k)) : LIMIT;
}
mark[i] = true;
for (int k=0; k<vCount(); ++k)
{
E m = LIMIT;
int u = -1;
for (int w=0; w<vCount(); ++w)
{
if (!mark[w] && dist[w] < m)
{
m = dist[w];
u = w;
}
}
if (u == -1)
{
break;
}
mark[u] = true;
for (int w=0; w<vCount(); ++w)
{
if (!mark[w] && isAdjacent(u, w) && (dist[u] + getEdge(u, w) < dist[w]))
{
dist[w] = dist[u] + getEdge(u, w);
path[w] = u;
}
}
}
LinkStack<int> s;
s.push(j);
for (int k=path[j]; k!=-1; k=path[k])
{
s.push(k);
}
while (s.size() > 0)
{
ret.add(s.top());
s.pop();
}
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "Parameter <i, j> is invalid ...");
}
if (ret.length() < 2)
{
THROW_EXCEPTION(ArithmeticExcption, "This is no path from i to j ...");
}
return toArray(ret);
}
SharedPointer<Array<int>> floyd(int x, int y, const E &LIMIT)
{
LinkQueue<int> ret;
if ((0 <= x) && (x < vCount()) && (0 <= y) && (y < vCount()))
{
DynamicArray<DynamicArray<E>> dist(vCount());
DynamicArray<DynamicArray<int>> path(vCount());
for (int k=0; k<vCount(); ++k)
{
dist[k].resize(vCount());
path[k].resize(vCount());
}
for (int i=0; i<vCount(); ++i)
{
for (int j=0; j<vCount(); ++j)
{
dist[i][j] = isAdjacent(i, j) ? (path[i][j] = j, getEdge(i, j)) : LIMIT;
}
}
for (int k=0; k<vCount(); ++k)
{
for (int i=0; i<vCount(); ++i)
{
for (int j=0; j<vCount(); ++j)
{
if (dist[i][j] > (dist[i][k] + dist[k][j]))
{
dist[i][j] = dist[i][k] + dist[k][j];
path[i][j] = path[i][k];
}
}
}
}
while ((x != -1) && (x != y))
{
ret.add(x);
x = path[x][y];
}
if (x != -1)
{
ret.add(x);
}
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter <x, y> is invalid ...");
}
if (ret.length() < 2)
{
THROW_EXCEPTION(ArithmeticExcption, "This is no path from x to y ...");
}
return toArray(ret);
}
protected:
template <typename T>
DynamicArray<T>* toArray(LinkQueue<T> &queue)
{
DynamicArray<T> *ret = new DynamicArray<T>(queue.length());
if (ret != nullptr)
{
for (int i=0; i<ret->length(); ++i, queue.remove())
{
ret->set(i, queue.front());
}
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create ret obj ...");
}
return ret;
}
#ifdef DFS_R
void DFP(int i, DynamicArray<bool> &visited, LinkQueue<int>& queue)
{
if (!visited[i])
{
queue.add(i);
visited[i] = true;
SharedPointer<Array<int>> aj = getAdjacent(i);
for (int j=0; j<aj->length(); ++j)
{
DFP((*aj)[j], visited, queue);
}
}
}
#endif
int find(Array<int> &p, int v)
{
while (p[v] != -1)
{
v = p[v];
}
return v;
}
SharedPointer<Array<Edge<E>>> getUndirectedEdges()
{
DynamicArray<Edge<E>> *ret = nullptr;
if (asUndirected())
{
LinkQueue<Edge<E>> queue;
for (int i=0; i<vCount(); ++i)
{
for (int j=0; j<vCount(); ++j)
{
if (isAdjacent(i, j))
{
queue.add(Edge<E>(i, j, getEdge(i, j)));
}
}
}
ret = toArray(queue);
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "This function is for undirected graph only ...");
}
return ret;
}
};
}
#endif // GRAPH_H
文件:main.cpp
#include <iostream>
#include "MatrixGraph.h"
#include "ListGraph.h"
using namespace std;
using namespace DTLib;
template< typename V, typename E >
Graph<V, E>& GraphEasy()
{
static MatrixGraph<4, V, E> g;
g.setEdge(0, 1, 1);
g.setEdge(0, 2, 3);
g.setEdge(1, 2, 1);
g.setEdge(1, 3, 4);
g.setEdge(2, 3, 1);
return g;
}
template< typename V, typename E >
Graph<V, E>& GraphComplex()
{
static ListGraph<V, E> g(5);
g.setEdge(0, 1, 10);
g.setEdge(0, 3, 30);
g.setEdge(0, 4, 100);
g.setEdge(1, 2, 50);
g.setEdge(2, 4, 10);
g.setEdge(3, 2, 20);
g.setEdge(3, 4, 60);
return g;
}
template< typename V, typename E >
Graph<V, E>& GraphSample()
{
static ListGraph<V, E> g(3);
g.setEdge(0, 1, 4);
g.setEdge(0, 2, 11);
g.setEdge(1, 2, 2);
g.setEdge(1, 0, 6);
g.setEdge(2, 0, 3);
return g;
}
void func1()
{
Graph<int, int> &g = GraphSample<int, int>();
SharedPointer<Array<int>> r = g.floyd(0, 2, 65535);
for (int i=0; i<r->length(); ++i)
{
cout << (*r)[i] << " ";
}
cout << endl;
}
void func2()
{
Graph<int, int> &g = GraphComplex<int, int>();
SharedPointer<Array<int>> r = g.floyd(0, 4, 65535);
for (int i=0; i<r->length(); ++i)
{
cout << (*r)[i] << " ";
}
cout << endl;
}
int main()
{
func1();
func2();
return 0;
}
输出:
0 1 2
0 3 2 4
小结
- Floyd 算法通过递推逐步求得所有顶点间的路径
- Floyd 算法的本质是通过中转顶点寻求更短的路径
- 邻接矩阵是最短路径推导的起始矩阵
- 路径矩阵记录了最短路径上的各个点
以上内容整理于狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。