前段时间要做一个Project,在建模过程中发现要求出一个网络拓扑中的前K条最短路才能进行后续的运算,自己研究了一段时间,实现了java版本的YEN--ksp算法。
Yen's算法是Yen 在1971 年提出的以其名字命名 的Yen 算法。Yen's算法基于偏离路径算法思想,算法原理详见https://en.wikipedia.org/wiki/Yen%27s_algorithm
我自己实现的这个算法比较粗糙,还有不少可以优化的地方,比如第一次Dijkstra(s)的时候可以把路径信息存储起来,以便后续无需计算直接使用,这里我就不实现了。
算法所需的数据采用随机生成的方式,并且将设置YEN_ksp(0,55,50),即求出Node-0到Node-55的前50条最短路
package lib.utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
public class Yen_Ksp {
public static int n=100;//节点数
public static double[][] edges=new double[n][n];
public static double[][] edges_tmp=new double[n][n];
public static ArrayList ans_path=new ArrayList<>();//K最短路径
public static Map dev_path_sql=new HashMap();//用于查询偏离路径是否重复
public static Queue dev_path_queue = new PriorityQueue<>();//用于存放偏离路径
public static boolean[] s=new boolean[n];//待扩展的节点集合,false:未扩展
public static int[] prev_node=new int[n];//存放前向节点
public static double[] dist=new double[n];//路径的权重和
public static final double INF=10000000;
public static void Dijkstra(int v0){//v0-> otherNode
for(int i=0;i getPath(int s,int t){
ArrayList v=new ArrayList<>();
if(s==t) return v;
v.add(t);
int tmp=t;
while(tmp!=s){
tmp=prev_node[tmp];//tmp的前向节点
v.add(tmp);
}
Collections.reverse(v);
return v;
}
public static void set_link(ArrayList p1,int s_node) {//p1:待检测的path,s_node:p1的末结点
int len=ans_path.size();
int len_p=p1.size();
for(int i=0;i p2=ans_path.get(i).path;
if(len_p>=p2.size()) continue;
boolean flag=true;
for(int j=0;jk 设置为INF
edges_tmp[s_node][k]=INF;
}
}
}
}
}
public static void recover_link(int s_node) {
for(int k=0;k0) {
if(!ans_path.contains(p)) ans_path.add(p);
else continue;
int len=p.path.size();
ArrayList path_tmp=new ArrayList<>();//p的部分迭代路径
for(int i=0;i=INF) continue;//没有路径了
Path pp=new Path(getPath(s,t),dist[t]);//修正后的最短路(偏离路径)
// if(!dev_path_sql.containsKey(pp)) {
// dev_path_queue.add(pp);
// dev_path_sql.put(pp.clone(), true);
// }
if(!dev_path_queue.contains(pp)) {
dev_path_queue.add(pp);
}
}
if(dev_path_queue.isEmpty()) break;
p=dev_path_queue.remove();
//dev_path_sql.remove(p);
}
}
public static void main(String[] args) {
Random r=new Random();
//先生成一个树
edges[0][1]=r.nextDouble()*10+10;
edges[1][0]=r.nextDouble()*10+10;
for(int i=1;i0) {//已经有边了
//edges[i][j]+=r.nextDouble()*50+50;
;
}else {//没边
if(r.nextDouble()>0) {//0.5的概率生成边
edges[i][j]=r.nextDouble()*100+500;
}else {
edges[i][j]=INF;
}
}
}
}
System.out.println("YEN_ksp start:");
YEN_ksp(0,55,50);//求出结点0到结点55的前50条最短路
int len=ans_path.size();
System.out.println(len);
for(int i=0;i
封装的path.java:
package lib.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class Path implements Comparable,Cloneable{
public ArrayList path;
double dist;
public Path(ArrayList path,double dist){
this.path=path;
this.dist=dist;
}
@Override
public int compareTo(Object o) {
Path p=(Path)o;
if(this.dist>p.dist) return -1;
else if(this.dist==p.dist) return 0;
else return 1;
}
@Override
public int hashCode() {
return path.hashCode()+(int)dist;
}
@Override
public boolean equals(Object obj) {
Path p=(Path)obj;
if(this.dist!=p.dist) return false;
int len1=this.path.size();
int len2=p.path.size();
if(len1!=len2) return false;
for(int i=0;i)this.path.clone();
tmp.dist=this.dist;
return tmp;
}
// public static void main(String[] args) {
// Map dev_path_sql=new HashMap();
// ArrayList v1= new ArrayList<>();
// v1.add(1);
// v1.add(2);
// ArrayList v2= new ArrayList<>();
// v2.add(1);
// v2.add(2);
// Path p1=new Path(v1,10);
// Path p2=new Path(v2,10);
// dev_path_sql.put(p1.clone(), true);
// System.out.println(dev_path_sql.containsKey(p2));
// p1.path.add(3);
// System.out.println(dev_path_sql.containsKey(p2));
// dev_path_sql.put(new Path(v2,10), true);
// System.out.println(dev_path_sql.size());
// dev_path_sql.remove(new Path(v2,10));
// System.out.println(dev_path_sql.size());
// }
}
运行结果如下:
YEN_ksp start:
50
0 1 55 dist: 521.530
0 53 54 55 dist: 563.921
0 56 55 dist: 567.054
0 57 56 55 dist: 567.667
0 59 58 57 56 55 dist: 573.120
0 52 53 54 55 dist: 574.652
0 50 51 52 53 54 55 dist: 586.064
0 58 57 56 55 dist: 589.331
0 55 dist: 590.887
0 54 55 dist: 613.887
0 47 48 49 50 51 52 53 54 55 dist: 626.572
0 60 59 58 57 56 55 dist: 644.148
0 49 50 51 52 53 54 55 dist: 649.717
0 51 52 53 54 55 dist: 652.126
0 65 64 63 62 61 60 59 58 57 56 55 dist: 656.914
0 48 49 50 51 52 53 54 55 dist: 676.458
0 63 62 61 60 59 58 57 56 55 dist: 687.190
0 62 61 60 59 58 57 56 55 dist: 688.555
0 61 60 59 58 57 56 55 dist: 689.318
0 44 45 46 47 48 49 50 51 52 53 54 55 dist: 694.788
0 64 63 62 61 60 59 58 57 56 55 dist: 695.797
0 66 65 64 63 62 61 60 59 58 57 56 55 dist: 703.198
0 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 705.473
0 46 47 48 49 50 51 52 53 54 55 dist: 723.243
0 45 46 47 48 49 50 51 52 53 54 55 dist: 734.643
0 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 738.297
0 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 740.333
0 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 749.203
0 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 761.700
0 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 769.119
0 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 780.547
0 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 784.978
0 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 793.785
0 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 800.300
0 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 802.399
0 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 810.460
0 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 813.899
0 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 818.640
0 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 829.547
0 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 831.752
0 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 832.565
0 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 836.453
0 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 841.897
0 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 852.720
0 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 867.588
0 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 874.265
0 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 876.927
0 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 880.461
0 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 dist: 884.851
0 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 dist: 886.536
另一个基于链表的实现,详见本人github: https://github.com/xycodec/CodeCraft_2019_public/blob/master/src/main/java/com/huawei/graph/Graph.java#L470