该算法主要流程如下:
1、构建有向图
2、往构建的有向图中新增虚拟节点,从该虚拟节点出发连接各点,权重设置为0
3、利用Bellman-Ford算法,算出新增虚拟节点到各点的最短距离,放入节点内部
4、对各边重新赋值,赋值公式为 “原权值+出发点节点内部的值-终点节点内部的值”
5、去掉虚拟节点,留下的图即放入Dijkstra的图
6、接着跑Dijkstra算法,每次选用一个点为起点,算出该点到其他各点的最短距离。每次算完后再轮换起点的节点。可以得到一个n*n的矩阵,其中n为点数。矩阵中的值为最短路径。
7、结果矩阵 = Dijkstra算法得到的矩阵中的每个值+该路径终点节点内部的值-该路径出发点的节点内部的值。
构建有向图
/创建有向图
Graph CreateGraph(vector>matrix) //matrix的每行结构为[出发点,终点,边权值]
{
Graph graph;
for (int i = 0; i < matrix.size(); i++)
{
int from = matrix[i][0];
int to = matrix[i][1];
int weight = matrix[i][2];
if(graph.nodes.find(from) == graph.nodes.end())
{
graph.nodes[from] =* new Node(from);
}
if (graph.nodes.find(to) == graph.nodes.end())
{
graph.nodes[to] = *new Node(to);
}
graph.nodes[from].nexts.push_back(graph.nodes[to]);//出发点指向的点中 加入 终点
graph.nodes[from].out++;//出发点出度++
graph.nodes[to].in++;//终点入度++
Edge newEdge(weight, graph.nodes[from], graph.nodes[to]);//构造当前边
graph.edges.push_back(newEdge);
graph.nodes[from].edges.push_back(newEdge);//出发点的边集中加入当前边
}
return graph;
}
新增虚拟节点
//新增虚拟节点
Graph CreateNewGraph(Graph graph)
{
graph.nodes[0] = *new Node(0);
for (int i = 1; i < graph.nodes.size(); i++)
{
Edge newEdge(0, graph.nodes[0], graph.nodes[i]);//构造当前边
graph.edges.push_back(newEdge);
graph.nodes[i].in++;
graph.nodes[0].out++;
}
return graph;
}
BellmanFord算法
//BellmanFord算法
bool BellmanFord(Graph graph, Node head, map& distanceMap)
{
for (int i = 1; i < graph.nodes.size(); i++)
{
Node node = graph.nodes[i];
distanceMap[node] = MAX;
}
distanceMap[head] = 0; //源节点到自身的距离设为0
//n-1次循环求最短路径
for (int i = 1; i < graph.nodes.size(); i++)
{
for (int j = 0; j < graph.edges.size(); j++)
{
if (distanceMap[graph.edges[j].to] > distanceMap[graph.edges[j].from] + graph.edges[j].weight)
{
distanceMap[graph.edges[j].to] = distanceMap[graph.edges[j].from] + graph.edges[j].weight;
}
}
}
bool flag = true; //标记是否有负权回路
//第n次循环判断负权回路
for (int i = 0; i < graph.edges.size(); i++)
{
if (distanceMap[graph.edges[i].to] > distanceMap[graph.edges[i].from] + graph.edges[i].weight)
{
flag = false;
break;
}
}
return flag;
}
对各边重新赋值,该部分代码和构建有向图类似
Graph ResetWeight(Graph graph, map& distanceMap, vector> matrix)
{
for (int i = 0; i < graph.edges.size(); i++)
{
graph.edges[i].weight = graph.edges[i].weight + distanceMap[graph.edges[i].from] - distanceMap[graph.edges[i].to];
}
Graph Newgraph;
int j = 0;
for (int i = 0; i < matrix.size(); i++)
{
int from = matrix[i][0];
int to = matrix[i][1];
int weight = graph.edges[j++].weight;
if (Newgraph.nodes.find(from) == Newgraph.nodes.end())
{
Newgraph.nodes[from] = *new Node(from);
}
if (Newgraph.nodes.find(to) == Newgraph.nodes.end())
{
Newgraph.nodes[to] = *new Node(to);
}
Newgraph.nodes[from].nexts.push_back(Newgraph.nodes[to]);//出发点指向的点中 加入 终点
Newgraph.nodes[from].out++;//出发点出度++
Newgraph.nodes[to].in++;//终点入度++
Edge newEdge(weight, Newgraph.nodes[from], Newgraph.nodes[to]);//构造当前边
Newgraph.edges.push_back(newEdge);
Newgraph.nodes[from].edges.push_back(newEdge);//出发点的边集中加入当前边
}
return Newgraph;
}
Dijkstra算法
Node getMinDistanceAndUnselectedNode(map distanceMap, set touchedNodes)
{
Node minNode =* new Node(-1);
int minDistance = MAX;
for (auto entry : distanceMap)
{
Node node = entry.first;
int distance = entry.second;
if (touchedNodes.find(node) == touchedNodes.end() && distance < minDistance)
{
minNode = node;
minDistance = distance;
}
}
return minNode;
}
//Dijkstra算法
map Dijkstra(Graph graph, Node head)
{
//head 出发到所有点的最小距离
//key:从head出发到到达key
//value:从head出发到达key的最小距离
//如果在表中,没有T的记录,则从head出发到T这个点的距离为正无穷
map distanceMap;
distanceMap[head] = 0; //将头节点放入
//已经求过距离的节点,存在selectedNodes中,以后再也不碰
set selectedNodes;
Node minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes); //从distanceMap中寻找除了selectedNodes以外的最短距离点
while ( minNode.value != -1)
{
int distance = distanceMap[minNode];
for (Edge edge : graph.nodes[minNode.value].edges)
{
Node toNode = edge.to;
if(distanceMap.find(toNode) == distanceMap.end())
distanceMap[toNode] = distance + edge.weight;
distanceMap[edge.to] = min(distanceMap[toNode], distance + edge.weight);
}
selectedNodes.insert(minNode);
minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes);
}
return distanceMap;
}
Dijkstra的结果矩阵如下图所示:
第一行为1号节点到各点的最短距离,如第一行第一列的0表示1号节点到1号节点的最短距离为0,第一行第二列的2表示1号节点到2号节点的最短距离为2……以此类推。
Main(),再主函数中得到结果矩阵
int main()
{
std::cout << "Hello World!\n";
int cols = 3;
cout << "请输入点数" << endl;
int num = 0;
cin >> num;
vector> matrix = { {1,2,3},{1,5,-4},{1,3,8},{2,5,7},{2,4,1},{3,2,4},{4,1,2},{4,3,-5},{5,4,6} };
/* 手动输入时的代码
int rows = 0;
cout << "请输入边数" << endl;
cin >> rows;
vector> matrix(rows, vector(cols, 0));
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
{
cin >> matrix[i][j];
}
*/
std::cout << "Process……\n";
//创建图
Graph graph = CreateGraph(matrix);
//新增虚拟节点
Graph NewGraph = CreateNewGraph(graph);
//BellmanFord算法
map BFdistanceMap;
if (!BellmanFord(NewGraph, NewGraph.nodes[0], BFdistanceMap)) //BFdistanceMap里是δ(s,v),即h(v)
std::cout << "the input graph contains a negative-weight cycle"< SinglePointDJ;
vector> ResultDJ;
for (int i = 1; i <= num; i++)
{
Node head = graph.nodes[i];
map distanceMap = Dijkstra(graph, head);
for (int j = 1; j <= num; j++)
{
SinglePointDJ.push_back(distanceMap[graph.nodes[j]]);
cout << distanceMap[graph.nodes[j]] << " ";
}
ResultDJ.push_back(SinglePointDJ);
cout << endl;
SinglePointDJ.clear();
}
vector> ResultD = ResultDJ;
for (int i = 0; i < ResultDJ.size(); i++)
{
for (int j = 0; j < ResultDJ[0].size(); j++)
{
ResultD[i][j] = ResultDJ[i][j] - BFdistanceMap[graph.nodes[i+1]] + BFdistanceMap[graph.nodes[j+1]];
cout << ResultD[i][j]<<" ";
}
cout << endl;
}
std::cout << "finish!\n";
}
得到最终的结果矩阵。