实验四分支限界法实现单源最短路径
09电信实验班I09660118 徐振飞
一、实验名称
实现书本P194页所描述的单源最短路径问题
二、实验目的
(1)掌握并运用分支限界法基本思想
(2)运用分支限界法实现单源最短路径问题
(3)区分分支限界算法与回溯算法的区别,加深对分支限界法理解三、实验内容和原理
(1)实验原理
解单源最短路径问题的优先队列式分支限界法用一极小堆(本次实验我采用java.util包中的优先队列类PriorityQueue来实现)来存储活结点表。
其优先级是结点所对应的当前路长。
算法从图G的源顶点s和空优先队列开始。
结点s被扩展后,它的儿子结点被依次插入堆中。
此后,算法从堆中取出具有最小当前路长的结点作为当前扩展结点,并依次检查与当前扩展结点相邻的所有顶点。
如果从当前扩展结点i到顶点j有边可达,且从源出发,途经顶点i再到顶点j的所相应的路径的长度小于当前最优路径长度,则将该顶点作为活结点插入到活结点优先队列中。
这个结点的扩展过程一直继续到活结点优先队列为空时为止。
(2)实验内容测试用例:
1
2
3
4
5
6 3
4
2
7
6
13
9
5
四、源程序
import java.util.*;
public class ShortestPath
{
private int n;
private double matrix[][] = null;
private double minpath[];
public ShortestPath(int n)
{
this.n = n;
matrix = new double[n+1][n+1];
minpath = new double[n+1];
for(int i=1;i<=n;i++)
{
minpath[i] = Double.MAX_VALUE;
}
//初始化图
getGraphMatrix();
}
public void getGraphMatrix()
{
//初始化为不能连通
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
matrix[i][j] = Double.MAX_VALUE;
}
}
System.out.println("请输入边总数:");
Scanner scan = new Scanner(System.in);
int m = scan.nextInt();
System.out.println("依次输入两个顶点号(1~"+n+")和边长:例如 1 2 3");
for(int i=0;i<m;i++)
{
int a,b;
double d;
a = scan.nextInt();
b = scan.nextInt();
d = scan.nextDouble();
if(a<1 || b<1)
{
i--;
System.out.println("顶点号不能小于1");
continue;
}
if(a>n||b>n)
{
i--;
System.out.println("顶点号不能大于"+n);
continue;
}
matrix[a][b] = d;
}
}
/**
*@param求以第i个节点为起点的单源最短路径
*/
public void shortpath(int i)
{
minpath[i] = 0;
double curlen = 0;
PriorityQueue<Node> heap = new PriorityQueue();
Node cur = new Node(i,0);
heap.add(cur);
while(!heap.isEmpty())
{
for(int j=1;j<=n;j++)
{
if(matrix[cur.i][j]<Double.MAX_VALUE&& cur.len+matrix[cur.i][j]<minpath[j])
{
minpath[j] = cur.len+matrix[cur.i][j];
heap.add(new Node(j,minpath[j]));
}
}
cur = heap.poll();
}
//打印最短路径结果
System.out.println("最短路径:");
for(int j=1;j<=n;j++)
{
if(minpath[j]<Double.MAX_VALUE && j!=i)
{
System.out.println(i+"到"+j+":"+minpath[j]);
}
}
}
public static void main(String args [])
{
System.out.println("请输入定点总数:");
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
ShortestPath s = new ShortestPath(n); s.shortpath(1);
}
}
class Node implements Comparable<Node>
{
int i;
double len;
public Node(int i,double l)
{
this.i = i;
len = l;
}
public int compareTo(Node o)
{
double dif = len-o.len;
if(dif>0)
{
return 1;
}
else if(dif==0)
{
return 0;
}
else
{
return -1;
}
}
}
五、实验结果
输出结果分析:测试为上述测试用途,输出结果:1到2的最短路径为3,1到3的最短路径为2,1到4的最短路径为3,1到5的最短路径为7,1到6的最短路径为6。
输出结果正确。
六、实验心得和体会
通过实验,了解了分支限界法的基本思想。
知道了分支限界算法与回溯算法的区别。
由于本次实验利用java.util包下的PriorityQueue代替算法中最小堆,免去了编写实现最小堆的程序代码(但这并不表示我不会编写最小堆程序,在这次实验中,最小堆的实现并不是主要部分),所以本次实验实现的相对顺利。