单源最短路径问题
一、实验目的:
1、理解分支限界法的剪枝搜索策略;
2、掌握分支限界法的算法柜架;
3、掌握分支限界法的算法步骤;
4、通过应用范例学习动态规划算法的设计技巧与策略;
二、实验内容及要求:
1、使用分支限界法解决单源最短路径问题。
2、通过上机实验进行算法实现。
3、保存和打印出程序的运行结果,并结合程序进行分析,上交实验报告。
三、实验原理:
1.创建一个实现Comparable接口的节点类HeapNode,该类具有两个属性,分别是节点编号index和源点到该节点的最短距离length。同时在该类中重写compareTo方法,使用最短距离length属性作为比较条件,从小到大排序。
2.函数shortest()开始创建一个LinkedList对象,元素类型为HeapNode类,由于其本质是一个双向链表且元素HeapNode类具有compareTo方法,因此可以充当优先级队列。将各顶点的最短距离赋值为Float.MAX_VALUE,完成初始化工作。While循环完成最短距离的更新工作,对于当前的扩展结点, 依次检查与之相邻的所有顶点。如果从源点经顶点node到顶点i的路径长度小于当前的最短距离,就更新顶点i的最短距离并将顶点node作为顶点i的前趋节点,将顶点i加入到链表对象中,重新进行链表排序,找到当前距离源点最近的顶点,最后取出链表中的头节点,实现扩展结点更新。当链表为空时,退出循环,得到最短距离。
四、源代码
import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
public class ShortestPath {
/**
* 节点类
*/
private static class HeapNode implements Comparable {
// 当前节点的编号
private int index;
// 当前到达此节点的最短距离
private float length;
public HeapNode(int index,float length) {
this.index = index;
this.length = length;
}
/**
* 重写compareTo方法,便于排序使用
* @param object : 另一个节点
* @return
*/
@Override
public int compareTo(Object object) {
float len = ((HeapNode) object).length;
return (length < len) ? 1:0;
}
}
/**
* 分支限界(单源最短路径)
* @param a : 两点间的距离数组
* @param dist : 当前最短距离数组
* @param origin : 源点编号
* @param prev : 前趋节点数组
*/
public static void shortest(float[][] a,float[] dist,int origin,int[] prev) {
// 顶点数量
int n = prev.length - 1;
// 创建节点链表
LinkedList<HeapNode> nodes = new LinkedList<>();
// 创建源节点
HeapNode node = new HeapNode(origin,0);
for (int i = 1;i <= n;++i) {
// 初始化最短距离为Float.MAX_VALUE
dist[i] = Float.MAX_VALUE;
}
while (true) {
for (int i = 1;i <= n;++i) {
// 两节点间存在路径且到节点node的距离加两点间距离小于当前到节点i的最短距离
if (a[node.index][i] != -1 && node.length + a[node.index][i] < dist[i]) {
// 更新当前到节点i的最短距离
dist[i] = node.length + a[node.index][i];
// 更新节点i的前趋节点
prev[i] = node.index;
// 创建节点i对象
HeapNode heapNode = new HeapNode(i,dist[i]);
// 添加到链表中
nodes.add(heapNode);
// 按距离从短到长排序
Collections.sort(nodes);
}
}
// 链表为空退出循环
if (nodes.isEmpty()) {
break;
}else {
// 取出当前距离源点最近的节点
node = nodes.poll();
}
}
// 输出结果
for (int i = 2;i <= n;++i) {
System.out.println(i+"节点的最短距离是:"+dist[i]+";前驱点是:"+prev[i]);
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("请输入图的顶点数:");
// 创建顶点数量
int n = in.nextInt();
// 消除回车键影响
in.nextLine();
// 创建前趋节点数组
int[] prev = new int[n+1];
// 创建两点间距离数组
float[][] a = new float[n+1][n+1];
// 创建最短距离数组
float[] dist = new float[n+1];
System.out.println("请输入图的路径长度:");
for (int i = 0;i < n;++i) {
// 获得一行内容
String line = in.nextLine();
//将一个顶点到其他顶点的距离转成距离数组
String[] length = line.split(",");
for (int j = 0;j < length.length;++j) {
// 赋值
a[i+1][j+1] = Float.parseFloat(length[j]);
}
}
// 调用最短路径算法
shortest(a,dist,1,prev);
in.close();
}
}