单元最短路径问题 分支界限法


分支界限法类似于回溯法,也是在问题的解空间上搜索问题解的算法。回溯法以深度优先的方式搜索解空间,而分支界限法则以广度优先(队列式分支界限法)或者以最小消耗的方式(优先队列式分支界限法)搜索解空间。

队列式分支界限法:队列式分支界限法将活结点表组织成一个队列,并按照队列的先进先出原则选取下一个结点为当前扩展结点。而且队列式分支界限法不搜索以不可行结点为根的子树。

优先队列式分支界限法:优先队列式分支界限法将活结点表组织成一个优先队列,并按照优先队列中规定的结点优先级选取下一个结点成为当前扩展结点,用优先队列式分支界限法解具体问题时,应根据具体问题的特点选用最大优先队列或者最小优先队列表示解空间的活结点表。



单元最短路径问题:所给的有向图G中,每一条边都有一个非负边权。要求图G的源顶点s到目标顶点t之间的最短路径。解单源最短路径问题的优先队列式分支界限法用一极小堆来储存活结点表。其优先级是结点所对应的当前路长。

单元最短路径问题 分支界限法_第1张图片


         下图是用优先队列式分支界限法解有向图G的单源最短路劲问题所产生的解空间树。每一个结点旁边的数字表示该结点所对应的当前路长。由于图G中各边的权非负,所以结点对应的当前路长也是解空间树中以该结点为根的子树中所有结点所对应路长的一个下界。在算法的扩展结点中,一旦发现一个结点的下界不小于当前找到的最短路长,则算法剪去以该结点为根的子树。

   一开始结点s被扩展后,它的三个儿子结点被依次插入堆中。此后算法从堆中取出具有最小当前路长的结点作为当前扩展结点,并依次检查与当前扩展结点相邻的所有顶点。如果从当前扩展结点i到j有变可达,且从源出发,途径顶点i再到达顶点j的所相应的路径长度小于当前最优路径长度,则将该顶点作为活结点插入到活结点优先队列中。直到活结点优先队列为空为止。

   例如一开始堆里有a->O,   b->O    c->O这三个结点(表示例如路径a到达的结点),a->O的优先级最高,所以作为当前扩展结点,且u->O,e->O,d->O也入堆。堆里下一个优先级高的是b->O,所以作为当前扩展结点.........

单元最短路径问题 分支界限法_第2张图片


在算法中,利用结点间的控制关系进行剪枝可使得算法更佳。例如从原点s出发,经过a-e-q路长为5,和经过边c-h路长为6的两条路径到达图G的同一顶点,显然路径为a-e-q的比路径为c-h的号。因此可以把路径h以及以下的结点子树剪去。


算法框架如下:

template
class Graph{
	friend void main(void);
	public:
		void ShortestPaths(int);
	private:
		int n,				//图G顶点数
			*prev;			//前驱顶点数组
		Type **c,			//图G的临接矩阵
			*dist;			//最短距离数组
};
//-----------------------------------------------
template
class MinHeapNode{
	friend Graph;
	public:
		operator int () const {return length;}
	private:
		int i;				//顶点编号
		Type length;		//当前路长
};
//------------------------------------------------
template
void Graph::ShortestPaths(int v)
{
	//单源最短路径问题的优先队列式分支算法
	//定义最小堆的容量为1000
	MinHeap>H(1000);
	//定义源为初始扩展结点
	MinHeapNodeE;
	E.i=v;
	E.length=0;
	dist[v]=0;
	//搜索问题的解空间
	while(true){
		for(int j=1;j<=n;j++)
			if((c[E.i][j]N;
				N.i=j;
				N.length=dist[j];
				H.Insert(N);}
			try{H.DeleteMin(E);}		//取下一个扩展结点
			catch(OutOfBounds){break;}  //优先队列空
	}
}


你可能感兴趣的:(算法初步)