分支限界法实验单源最短路径.docx
《分支限界法实验单源最短路径.docx》由会员分享,可在线阅读,更多相关《分支限界法实验单源最短路径.docx(12页珍藏版)》请在冰豆网上搜索。
![分支限界法实验单源最短路径.docx](https://file1.bdocx.com/fileroot1/2023-1/31/93ec0950-76bd-4517-99bb-f826bd5716c8/93ec0950-76bd-4517-99bb-f826bd5716c81.gif)
分支限界法实验单源最短路径
算法分析与设计实验报告
第七次实验
姓名
学号
班级
时间
12.26上午
地点
工训楼309
实验名称
分支限界法实验(单源最短路径)
实验目的
1.掌握并运用分支限界法的基本思想
2.运用分支限界法实现单源最短路径问题
实验原理
问题描述:
在下图所给的有向图G中,每一边都有一个非负边权。
要求图G的从源顶点s到目标顶点t之间的最短路径。
基本思想:
下图是用优先队列式分支限界法解有向图G的单源最短路径问题产生的解空间树。
其中,每一个结点旁边的数字表示该结点所对应的当前路长。
为了加速搜索的进程,应采用有效地方式选择活结点进行扩展。
按照优先队列中规定的优先级选取优先级最高的结点成为当前扩展结点。
实验步骤
(1)算法从图G的源顶点s和空优先队列开始。
结点s被扩展后,它的儿子结点被依次插入堆中;
(2)算法每次从堆中取出具有最小当前路长的结点作为当前扩展结点,并依次检查与当前扩展结点相邻的所有顶点;
(3)如果从当前扩展结点i到j有边可达,且从源出发,途经i再到j的所相应路径长度,小于当前最优路径长度,则将该顶点作为活结点插入到活结点优先队列中;
(4)结点扩展过程一直继续到活结点优先队列为空时为止。
关键代码
//单源最短路径问题的优先队列式分支限界法
template
voidGraph:
:
shortest_path(intv)
{
//定义最小堆的容量为1000
MinHeap>H(1000);
//定义源为初始扩展结点
MinHeapNodeE;
//初始化源结点
E.i=v;
E.length=0;
dist[v]=0;
while(true)//搜索问题的解空间
{
for(intj=1;j<=n;j++)
if((c[E.i][j]!
=0)&&(E.length+c[E.i][j]{
//顶点i到顶点j可达,且满足控制约束
//顶点i和j之间有边,且此路径小于原先从源点到j的路径长度
dist[j]=E.length+c[E.i][j];//更新dist数组
prev[j]=E.i;
//加入活结点优先队列
MinHeapNodeN;
N.i=j;
N.length=dist[j];
H.Insert(N);//插入到最小堆中
}
try
{
H.DeleteMin(E);//取下一扩展结点
}
catch(int)
{
break;
}
if(H.currentsize==0)//优先队列空
{
break;
}
}
}
测试结果
上述有向图的结果:
实验分析
在实验中并没有生成多组数据,进行比较,也没有利用随机生成函数,因为在这种有实际有关联的问题中,利用随机生成函数生成的数据是十分的不合适的,在此我们只需要验证该程序是否正确即可。
分支限界法求单源最短路径问题与回溯法求单源最短路径问题其大致思想是一致的,都是利用解空间树,搜索子集树,回溯法是利用深度优先搜索子集树,而分支限界法是利用广度优先搜索子集树,然后利用队列或优先队列,最小堆存放可扩展的结点,然后将活结点出堆,从而直到堆空为止,找到最优解。
实验心得
在这一章的分支限界法中,与上一章的回溯法很相似,都是利用解空间树进行搜索,从而找到最优解。
不同的是回溯法利用的是深度优先回溯寻找,能够找到所有的最优解;而分支限界法则是利用广度优先搜索子集树或者排序树,利用队列或者优先级队列的数据结构组织所有满足的结点,这样只要找到一种最优解就可以了,想对于回溯法来说时间上相对利用的没有那么多。
在这一章的学习上,由于会利用最小堆/最大堆,所以代码看起来比较复杂,堆的实现也比较复杂,这是这一章我学习的一个难点,不过正在渐渐攻克。
实验得分
助教签名
附录:
完整代码(分支限界法)
Shorest_path.cpp
//单源最短路径问题分支限界法求解
#include
#include
#include
#include"MinHeap2.h"
usingnamespacestd;
template
classGraph//定义图类
{
friendintmain();
public:
voidshortest_path(int);
private:
intn,//图的顶点数
*prev;//前驱顶点数组
Type**c,//图的邻接矩阵
*dist;//最短距离数组
};
template
classMinHeapNode//最小堆中的元素类型为MinHeapNode
{
friendGraph;
public:
operatorint()const{returnlength;}
private:
inti;//顶点编号
Typelength;//当前路长
};
//单源最短路径问题的优先队列式分支限界法
template
voidGraph:
:
shortest_path(intv)
{
MinHeap>H(1000);//定义最小堆的容量为1000
//定义源为初始扩展结点
MinHeapNodeE;
//初始化源结点
E.i=v;
E.length=0;
dist[v]=0;
while(true)//搜索问题的解空间
{
for(intj=1;j<=n;j++)
if((c[E.i][j]!
=0)&&(E.length+c[E.i][j]{
//顶点i到顶点j可达,且满足控制约束
//顶点i和j之间有边,且此路径小于原先从源点i到j的路径长度
dist[j]=E.length+c[E.i][j];//更新dist数组
prev[j]=E.i;
//加入活结点优先队列
MinHeapNodeN;
N.i=j;
N.length=dist[j];
H.Insert(N);//插入到最小堆中
}
try
{
H.DeleteMin(E);//取下一扩展结点
}
catch(int)
{
break;
}
if(H.currentsize==0)//优先队列空
{
break;
}
}
}
intmain()
{
intn=11;
intprev[12]={0,0,0,0,0,0,0,0,0,0,0,0};//初始化前驱顶点数组
intdist[12]={1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000};//初始化最短距离数组
cout<<"单源图的邻接矩阵如下:
"<int**c=newint*[n+1];
for(inti=1;i<=n;i++)//输入图的邻接矩阵
{
c[i]=newint[n+1];
for(intj=1;j<=n;j++)
{
cin>>c[i][j];
}
}
intv=1;//源结点为1
GraphG;
G.n=n;
G.c=c;
G.dist=dist;
G.prev=prev;
clock_tstart,end,over;//计算程序运行时间的算法
start=clock();
end=clock();
over=end-start;
start=clock();
G.shortest_path(v);//调用图的最短路径查找算法
//输出从源结点到目的结点的最短路径
cout<<"从S到T的最短路长是:
"<for(inti=2;i<=n;i++)//输出每个结点的前驱结点
{
cout<<"prev("<
}
for(inti=2;i<=n;i++)//输出从源结点到其他结点的最短路径长度
{
cout<<"从1到"<
"<}
for(inti=1;i<=n;i++)//删除动态分配时的内存
{
delete[]c[i];
}
delete[]c;
c=0;
end=clock();
printf("Thetimeis%6.3f",(double)(end-start-over)/CLK_TCK);//显示运行时间
cout<system("pause");
return0;
}
MinHeap.h
#include
template
classGraph;
template
classMinHeap//最小堆类
{
template
friendclassGraph;
public:
MinHeap(intmaxheapsize=10);//构造函数,堆的大小是10
~MinHeap(){delete[]heap;}//最小堆的析构函数
intSize()const{returncurrentsize;}//Size()返回最小堆的个数
TMax(){if(currentsize)returnheap[1];}//第一个元素出堆
MinHeap&Insert(constT&x);//最小堆的插入函数
MinHeap&DeleteMin(T&x);//最小堆的删除函数
voidInitialize(Tx[],intsize,intArraySize);//堆的初始化
voidDeactivate();
voidoutput(Ta[],intn);
private:
intcurrentsize,maxsize;
T*heap;
};
template
voidMinHeap:
:
output(Ta[],intn)//输出函数,输出a[]数组的元素
{
for(inti=1;i<=n;i++)
cout<cout<}
template
MinHeap:
:
MinHeap(intmaxheapsize)
{
maxsize=maxheapsize;
heap=newT[maxsize+1];//创建堆
currentsize=0;
}
template
MinHeap&MinHeap:
:
Insert(constT&x)
{
if(currentsize==maxsize)//如果堆中的元素已经等于堆的最大大小
return*this;//那么不能在加入元素进入堆中
inti=++currentsize;
while(i!
=1&&x{
heap[i]=heap[i/2];
i/=2;
}
heap[i]=x;
return*this;
}
template
MinHeap&MinHeap:
:
DeleteMin(T&x)//删除堆顶元素
{
if(currentsize==0)
{
cout<<"Emptyheap!
"<return*this;
}
x=heap[1];
Ty=heap[currentsize--];
inti=1,ci=2;
while(ci<=currentsize)
{
if(ciheap[ci+1])
ci++;
if(y<=heap[ci])
break;
heap[i]=heap[ci];
i=ci;
ci*=2;
}
heap[i]=y;
return*this;
}
template
voidMinHeap:
:
Initialize(Tx[],intsize,intArraySize)//堆的初始化
{
delete[]heap;
heap=x;
currentsize=size;
maxsize=ArraySize;
for(inti=currentsize/2;i>=1;i--)
{
Ty=heap[i];
intc=2*i;
while(c<=currentsize)
{
if(cheap[c+1])
c++;
if(y<=heap[c])
break;
heap[c/2]=heap[c];
c*=2;
}
heap[c/2]=y;
}
}
template
voidMinHeap:
:
Deactivate()
{
heap=0;
}