K短路径算法
算法背景
K 最短路径问题是最短路径问题的扩展和变形。1959 年,霍夫曼(Hoffman) 和帕夫雷(Pavley)在论文中第一次提出k 最短路径问题。 k 最短路径问题通常包括两类:有限制的k 最短路问题和无限制的K 最短路问题。 前者要求最短路径集合不含有回路,而后者对所求得的最短路径集合无限制。
算法简介
Yen's算法是Yen 在1971 年提出的以其名字命名 的Yen 算法。Yen's算法采用了递推法中的偏离路径算法思想,适用于非负权边的有向无环图结构。
算法实例:
调用K条最短路径算法,源C,目的H,K为3。B为偏离路径集合。
1.通过Dijkstra算法计算得到最短路径A^1
:C-E-F-H
,其中,花费为5,A[1] = C-E-F-H
;
2.将A[1]作为迭代路径,进行第一次迭代:
(1)以部分迭代路径(即A[1])C
路径中,C点为起点,将C-E
路径之间的权值设为无穷大,进行一次Dijkstra,得到路径A^2-1
:C-D-F-H
,花费为8,将A^2-1
路径加入B;
(2)以部分迭代路径(即A[1])C-E
路径中,E为起点,将E-F
路径之间的权值设为无穷大,进行一次Dijkstra,得到路径A^2-2
:C-E-G-H
,花费为7,将A^2-2
路径加入B;
(3)以部分迭代路径(即A[1])C-E-F
路径中,F为起点,将F-H
路径之间的权值设为无穷大,进行一次Dijkstra,得到路径A^2-3
:C-E-F-G-H
,花费为8,将A^2-3
路径加入B;
迭代完成,B集合中有三条路径:C-D-F-H
,C-E-G-H
,C-E-F-G-H
;选出花费最小的偏离路径C-E-G-H
,A[2] = C-E-G-H
,移出B集合。
3.将A[2]作为迭代路径,进行第二次迭代:
(1)以部分迭代路径(即A[2])C
路径中,C点为起点,将C-E
路径之间的权值设为无穷大,进行一次Dijkstra,得到路径A^3-1
:C-D-F-H
,但B集合已存在该路径,故不存在偏移路径;
(2)以部分迭代路径(即A[2])C-E
路径中,E点为起点,将E-G
、E-F
路径之间的权值设为无穷大 (注意,这里设置两条路径的权值原因是这两条路径分别存在于A[1]和A[2]中),进行一次Dijkstra,得到路径A^3-2
:C-E-D-F-H
,花费为8,将A^3-2
加入B;
(3)以部分迭代路径(即A[2])C-E-G
路径中,G点为起点,将C-H
路径之间的权值设为无穷大,不存在偏移路径。
迭代完成,B集合中有三条路径:C-D-F-H
,C-E-F-G-H
,C-E-D-F-H
;由于三条路径花费均为8,则根据最小节点数进行判断,选出偏离路径C-D-F-H
,A[3] = C-D-F-H
。
此时,选出了三条最短路径,分别是:
A[1] = C-E-F-H
A[2] = C-E-G-H
A[3] = C-D-F-H
头文件
#ifndef _GRAPH_H
#define _GRAPH_H
#include<stdio.h>
#include<stdlib.h>
#include<vector>
#include<iostream>
#include<fstream>
#include<sstream>
#include<stack>
using namespace std;
#define MAXNODE 99
#define INFINITY 9999
#define K 10
typedef int VertexType;
typedef int EdgeType;
typedef struct node{
VertexType adjnode;
struct node* next;
EdgeType weight;
}EdgeNode;
typedef struct vnode{
VertexType vertex;
EdgeNode* firstedge;
}VertexNode;
typedef struct MatrixGraph{
VertexType vexs[MAXNODE + 1]; //顶点表
EdgeType edges[MAXNODE + 1][MAXNODE + 1]; //邻接矩阵,可看作边表
}MGraph;
typedef struct Pathstruct{ //用于保存一条路径,里面有每一跳的点和该路径总距离
VertexType node[MAXNODE + 1];
EdgeType distance ;
int hop;
}Path;
typedef VertexNode AdjList[MAXNODE + 1];
class Graph{
public:
Graph(string filename);
~Graph(){};
void FindKpath();
void PrintOut();
void Dijkstra(VertexType);
Path Graph::Dijkstra(VertexType,VertexType);
void DijkstraAll();
void PrintShortestPath(VertexType);
void PrintShortestPathAll(void);
void KShortestPath(VertexType);
private:
MGraph mgraph;
// AdjList adjlist;
EdgeType **dist;
VertexType **pre;
Path **Kpath[K+1]; //存储路径,起点存在node[0].node[i]就是第i跳的点
int e,n; //n是节点数node,e是边数edge
};
#endif
源文件
#include "graph.h"
//邻接表方式构建图
Graph::Graph(string filename){
int j,k,w;
ifstream fin(filename,ios::in);
fin>>n;
fin>>e;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
mgraph.edges[i][j] = INFINITY;
}
mgraph.vexs[i] = i;
}
for(int i = 1;i <= e;i++){
fin>>j;
fin>>k;
fin>>w;
mgraph.edges[j][k] = w;
mgraph.edges[k][j] = w;
}
dist = (EdgeType **)malloc(sizeof(EdgeType*) * n);
pre = (VertexType **)malloc(sizeof(VertexType*) * n);
for(int i = 1; i <= K; i++){
Kpath[i] = (Path **)malloc(sizeof(Path) * n);
for(int j = 1; j <= n; j++)
Kpath[i][j] = (Path *)malloc(sizeof(Path) * n);
}
for( int i = 1; i <= n; i++){
dist[i] = (EdgeType *)malloc(sizeof(EdgeType) * n);
pre[i] = (VertexType *)malloc(sizeof(VertexType) *n);
}
}
//求出V点的所有最短路径,结果保存在类的变量Kpath[1][v][i]里面,1表示第一短路径,v、i表示从v到i,
//Kpath结构里,node[i]表示第几跳的点,node[0]是自身,也就是v,另外保存了总跳数和总距离
void Graph::Dijkstra(VertexType v){
bool s[MAXNODE];
for(int i = 1; i <= n; i++){
dist[v][i] = mgraph.edges[v][i];
s[i] = 0;
if(dist[v][i] == INFINITY)
pre[v][i] = 0;
else
pre[v][i] = v;
}
s[v] = 1;
dist[v][v] = 0;
for( int i = 2; i <= n; i++){
VertexType u = v;
EdgeType tmp = INFINITY;
for(int j = 1; j <= n; j++){
if(!s[j] && dist[v][j] < tmp){
tmp = dist[v][j];
u = j;
}
}
s[u] = 1;
for(int j = 1; j <= n; j++){
if(mgraph.edges[u][j] + dist[v][u] < dist[v][j]){
dist[v][j] = mgraph.edges[u][j] + dist[v][u];
pre[v][j] = u;
}
}
}
for(VertexType i = 1; i <= n; i++){
int counthop = 0;
EdgeType length = 0;
VertexType j = i;
while(pre[v][j] != 0){
length += mgraph.edges[j][pre[v][j]];
j = pre[v][j];
counthop++;
}
Kpath[1][v][i].hop = counthop;
Kpath[1][v][i].distance = length;
VertexType m = i;
while(counthop){//处理结果是路径node[1]即为第一跳,根据pre[][]把结果弄出来
Kpath[1][v][i].node[counthop] = m;
m = pre[v][m];
counthop--;
}
Kpath[1][v][i].node[counthop] = v;
}
}
//这个跟上面有很大重复,稍微改了下,接收两个点,返回两点之间的最短