BFS+优先队列解决单源最短路径问题

问题描述:

在图中找到从某一源点到给定一点的最短路径。

分析:

解单源最短路径问题的优先队列分支限界法用一极小堆来存储活节点表,其优先级是结点所对应的当前路长。算法从图G的源顶点和空优先队列开始。根结点s被拓展后,它的3个儿子结点被依次插入堆中。此后,算法从堆中取出具有最小当前路长的结点作为当前拓展结点,并依次检查与当前拓展结点相邻的所有顶点。如果从当前拓展结点到顶点i到顶点j有边可达,且从源出发,途径顶点i再到顶点j的所对应的路径的长度小于当前最优路径长度,则将该顶点作为活节点插入到活结点优先队列中。这个结点的拓展过程一直继续到活结点优先队列为空时为止。

在具体实现时,算法用邻接矩阵表示所给的图G。算法中用数组dist记录从源到各顶点的距离;数组p记录从源到各顶点的路径上的前驱顶点。

由于要找的是从源到各顶点的最短路径,所以选用最小堆表示该活结点优先队列。最小堆中的元素的类型为HeapNode。该节点包含域i用于记录该活结点所表示的图G中相应顶点的编号,length表示从源到该顶点的距离。

两种剪枝方法:

(1)在算法拓展结点的过程中,一旦发现一个节点的下界不小于当前找到的最短路长,则算法剪去以该节点为根的子树。

(2)利用结点间的控制关系进行剪枝。

算法描述如下:

class BBShortTest
{
static class HeapNode implements Comparable
{
int i;          //顶点编号
float length;   //当前路长
   HeapNode(int i,float length)
{
this.i=i;
this.length=length;
}
public int compareTo(Object x)
{
float xl=((HeapNode)x).length;
if(lengthif(length==xl)return 0;
return 1;
}
}
static float[][]a;                //图G的邻接矩阵
    public static void shortest(int v,float[]dist,int[]p)//v是源点,p记录从源到各顶点的路径上的前驱顶点,其余各个顶点
{
int n=p.length-1;
MinHeap heap=new MinHeap();
HeapNode enode=new HeapNode(v,0);
for(int j=1;j<=n;j++)
dist[j]=Float.MAX_VALUE;
dist[v]=0;//dist[]记录从源到各顶点的距离,初始化为无穷大。源到源本身的距离为0;
   while(true)   //搜索问题的解空间,广度优先搜索
{
for(int j=1;j<=n;j++)    //依次检查与当前顶点相邻的所有顶点
if(a[enode.i][j]  enode.length+a[enode.i][j]   {
dist[j]=enode.length+a[enode.i][j];
p[j]=enode.i;
HeapNode node=new HeapNode(j,dist[j]);//将结点j加入活结点队列
heap.put(node);
   }
if(heapisEmpty())break;           //取下一拓展结点
else enode=(HeapNode)heap.removeMin();




}
}


}

总结:

算法开始时创建一个最小堆,用于表示活结点的优先队列。堆中每个节点的length值是优先队列的优先级(在比较方法中确认)。接着算法将源顶点V初始化为当前拓展结点。

算法的while循环体完成对解空间内部结点的拓展。对于当前拓展结点,算法依次检查与当前拓展结点相邻的所有顶点。如果从当前拓展顶点i到顶点j有边可达,且从源出发,途径顶点i再到顶点j的所对应的路径长度小于当前最优路径长度,则将该顶点作为活结点插入到活结点优先队列中。完成对当前节点的拓展后,算法从活优先队列中取出下一个活结点作为当前拓展结点,重复上述节点的分支拓展,继续到活结点优先队列为空时为止。

分支限界法(广度优先搜索算法)以广度优先或以最小耗费优先的方式搜索解空间树。

你可能感兴趣的:(算法与数据结构)