因为这个求N个点的最短路径是将把所有可能的走法都可能尝试一遍,这样的话,如果计算十几个点之间的最短路径是没有问题的,但是问题就在如果超过二十个点位,那么最坏的情况就是需要计算20的阶乘个,这个计算是相当高的,可能会把线上的服务器打爆,或者计算几分钟,这都是不能忍受的,下面是我对这个算法的一些优化
/*
求出最短路径
*/
public class MinDis {
static double INF = 1e7;
static int N = 100;
static double[][] matrix ; //地图矩阵
static Node min;
static double bestl = INF;// 记录当前最短的路径长度
static List<Integer> nodes = new ArrayList<Integer>();
static PriorityQueue<Node> priorityQueue = new PriorityQueue<>(N);
// 优先队列的分支界限法搜索
public LinkedHashSet<Integer> Traveling(double[][] matrix){
for (int i = 2; i < matrix.length; i++) {
nodes.add(i);
}
//生成根节点
Node root = new Node(0, 1);
root.notThrough.addAll(nodes);
root.throughed.add(1);
// 生成所有要走的点节点
priorityQueue.add(root);
while (!priorityQueue.isEmpty()){
// 取出头部元素作为扩展节点
Node poll = priorityQueue.poll();
// 如果当前的未到达路径只有一个 不需要往下搜索
if (poll.notThrough.size()==1){
for (Integer not: poll.notThrough) {
// 如果当前节点和未达节点可联通
if (matrix[poll.id][not]!=INF && matrix[poll.id][not]+poll.c1 < bestl ){
bestl = matrix[poll.id][not]+poll.c1;
poll.throughed.add(not);
min=poll;
}
}
}
// 如果没有到达子节点 遍历该节点没有经过的节点
for (Integer noThrough : poll.notThrough){
// 如果当前节点和未达节点不可联通
if (matrix[poll.id][noThrough]==INF){
continue;
}
//并且 到达的路径小于当前最优解
if (matrix[poll.id][noThrough]+poll.c1 < bestl){
// 生成一个新结点
Node newNode = new Node(matrix[poll.id][noThrough] + poll.c1, noThrough);
HashSet<Integer> noth = new HashSet<>(poll.notThrough);
noth.remove(noThrough);
// 新结点去除上一个节点没通过的自己的Id
newNode.notThrough.addAll(noth);
// 新结点保存之前node经过的点
newNode.throughed.addAll(poll.throughed);
// 新结点记录经过的点
newNode.throughed.add(noThrough);
priorityQueue.add(newNode);
}
}
}
// System.out.println(bestl);
// System.out.println(min.throughed);
return min.throughed;
}
//内部类 node //根据c1大小实现优先级
class Node implements Comparable<Node> {
public double c1; // 当前已走过的路径长度
public int id; //点序号
public LinkedHashSet<Integer> throughed; // 当前已走过的点序号
public HashSet<Integer> notThrough; //当前未走过的点序号
public Node(double c1, int id) {
this.c1 = c1;
this.id = id;
this.notThrough= new HashSet<>();
this.throughed=new LinkedHashSet<>();
}
@Override
public int compareTo(Node o) {
return (int) (this.c1-o.c1);
}
}
// 传入N个位置点 生成每个点之间距离的矩阵
public double[][] createMatrix(List<double[]> locations){
int row = locations.size()+1;
double[][] matrix = new double[row][row];
// 遍历点位
for (int i = 0; i < locations.size(); i++) {
double[] A = locations.get(i);
// 遍历每一个点到其他点的距离
for (int j = i; j < locations.size() ; j++) {
if(i==j){
matrix[i+1][i+1]=INF;
continue;
}
double[] B = locations.get(j);
double distance = GPSUtil.Distance(A[1], A[0], B[1], B[0]);
// 矩阵填充
matrix[i+1][j+1] = distance;
matrix[j+1][i+1] = distance;
}
}
return matrix;
}
这个算法的缺点在于 这个优先队列 是根据当前的路径长度来判断计算的优先级的 当前走过的路径越短 优先级就越高 但是这个本身就是有问题的,如果根据这个来判断那么就会遍历的点位可能特别多
我在网上搜了好久 也没发现太好的算法