分枝限界法实验报告.docx
《分枝限界法实验报告.docx》由会员分享,可在线阅读,更多相关《分枝限界法实验报告.docx(10页珍藏版)》请在冰豆网上搜索。
![分枝限界法实验报告.docx](https://file1.bdocx.com/fileroot1/2022-11/30/f81dbdaa-0da1-4f78-bdd5-893837a2c12e/f81dbdaa-0da1-4f78-bdd5-893837a2c12e1.gif)
分枝限界法实验报告
一、课题名称
用分枝限界法求解单源最短路径问题
二、课题内容和要求
设计要求:
学习算法设计中分枝限界法的思想,设计算法解决数据结构中求解单源最短路径问题,编程实现:
(1)给出指定源点的单源最短路径;
(2)说明算法的时间复杂度。
三、需求分析
1.实现极小堆的创建,用来存储活结点表。
2.实现循环队列的创建、初始化、入队、出队等操作。
3.实现分支限界法来实现求解单元最短路径的算法。
4.实现最短路径的正确输出。
四、概要设计
建立工程MinPath.dsw,加入源文件main.cpp,头文件CirQueue.h,init.h,Minpath.h和output.h.CirQueue.h中实现极小堆的创建,循环队列的创建、初始化、入队、出队等操作,Minpath.h中实现分支限界法来实现求解单元最短路径的算法。
output.h中实现最短路径的正确输出。
如下图所示:
实验用例如下,通过邻接矩阵的方式写在init.h中:
五、详细设计
main函数:
#include
#include"init.h"
#include"CirQueue.h"
#include"MinPath.h"
#include"output.h"
voidmain()
{
intk;
intq;
cout<<"------------欢迎使用本系统---------------"<cout<<"------------请选择单元路径的起点:
---------------"<cout<<"------------提示:
输入"<<1<<"到"<cin>>k;
cout<<"------------请选择单元路径的终点:
---------------"<cin>>q;
while(k<1||k>11)
{
cout<<"------------提示:
输入"<<1<<"到"<cin>>k;
}
MinPath(k);
output(k,q);
}
init.h
constintsize=200;
constintinf=1000;//两点距离上界置为1000
constintn=12;//图顶点个数加1
intprev[n];//图的前驱顶点
intdist[]={0,inf,inf,inf,inf,inf,inf,inf,inf,inf,inf,inf};//最短距离数组
intc[n][n]={{0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,2,3,4,inf,inf,inf,inf,inf,inf,inf},
{0,inf,0,3,inf,7,2,inf,inf,inf,inf,inf},
{0,inf,inf,0,inf,inf,9,2,inf,inf,inf,inf},
{0,inf,inf,inf,0,inf,inf,2,inf,inf,inf,inf},
{0,inf,inf,inf,inf,0,inf,inf,3,3,inf,inf},
{0,inf,inf,inf,inf,inf,0,1,inf,3,inf,inf},
{0,inf,inf,inf,inf,inf,inf,0,inf,5,1,inf},
{0,inf,inf,inf,inf,inf,inf,inf,0,inf,inf,3},
{0,inf,inf,inf,inf,inf,inf,inf,inf,0,inf,2},
{0,inf,inf,inf,inf,inf,inf,inf,inf,2,inf,2},
{0,inf,inf,inf,inf,inf,inf,inf,inf,inf,inf,0},};//图的邻接矩阵
CirQueue.h
classMinHeapNode//创建极小堆用来存储活结点表
{
public:
inti;//顶点编号
intlength;//当前路长
};
classCirQueue//循环队列
{
private:
intfront,rear;//头指针和尾指针
MinHeapNodedata[size];
public:
CirQueue()//初始化建空队列
{
front=rear=0;
}
voidqueryIn(MinHeapNodee)//元素入队操作
{
if((rear+1)%size!
=front)//队列未满
{
rear=(rear+1)%size;//插入新的队尾元素
data[rear]=e;//在队尾插入元素
}
}
voidqueryOut()//元素出队操作
{
if(rear!
=front)
{
front=(front+1)%size;//删除队头元素
}
}
MinHeapNodegetQuery()//读取队头元素,但不出队
{
if(rear!
=front)
{
returndata[(front+1)%size];
}
returndata[1];
}
boolempty()//判断队列是否为空
{
returnfront==rear;
}
boolfull()//判断队列是否为满
{
return(rear+1)%size==front;
}
};//CirQueue结束
MainPath.h
voidMinPath(intv)
{
CirQueues;//定义源为初始扩展结点
MinHeapNodee;
e.i=v;
e.length=0;
dist[v]=0;
s.queryIn(e);//将源节点加入队列
while(true){
for(intj=1;jif(j>=n)
{
break;
}
MinHeapNodem=s.getQuery();
if((c[m.i][j]{
dist[j]=m.length+c[m.i][j];
prev[j]=m.i;
MinHeapNodemi;//加入活结点优先队列
mi.i=j;
mi.length=dist[j];
if(s.full())
{
break;
}
s.queryIn(mi);//元素入队
}
}//for循环结束
if(s.empty())
{
break;
}
s.queryOut();//当该结点的孩子结点全部入队后,删除该结点
}//while循环结束
}//方法结束
output.h
voidoutput(intk,intq)
{
intq1=q;
if(dist[q1]==1000){
cout<<"------------找不到此路径---------------"<return;
}
cout<<"最短路径长为:
"<cout<<"单源最短路径为:
";
inta[12]={0};
intt=q1;
ints=0;
for(inti=0;t!
=k;i++)
{
a[i]=prev[t];
t=prev[t];
s=s+1;
}
for(i=s-1;i>-1;i--){
cout<}
cout<cout<}
六、测试数据及其结果分析
1.选择起点:
1,终点:
11
1到11最短路径长为8,为1->3->7->10->11所获得。
2.选择起点:
2,终点:
9
2到9最短路径长为5,为2->6->9所获得。
3.选择起点8,终点2
8到2没有路径,输出“找不到此路径”。
4.选择起点11,终点1
11到1没有路径,输出“找不到此路径”。
七、调试过程中的问题
1.CirQueue.h中,函数getQuery()中在调试过程中出现warnig:
'CirQueue:
:
getQuery':
notallcontrolpathsreturnavalue.
解决方案:
在if语句下面加上returndata[1];使当rear=front时函数也返回一个值。
2.当两结点间没有路径时,程序执行时出现错误。
解决方案:
在输出函数output中加入下面代码
if(dist[q1]==1000){
cout<<"------------找不到此路径---------------"<return;
}
即当两结点无路径时,输出提示“找不到此路径”,程序执行时不会崩溃。
3.输出过程中,如何使结点按顺序输出?
定义一个数组a[],应用递归对存储前驱结点的数组prev[]从后往前求解,将得到的值赋给数组a[],最后逆向输出对应的数组a[],即得到正确的路径顺序。
如下:
for(inti=0;t!
=k;i++)
{
a[i]=prev[t];
t=prev[t];
s=s+1;
}
for(i=s-1;i>-1;i--){
cout<}
八、程序设计总结
本次实验回顾了用分枝限界法求解单源最短路径问题的思想,运用了优先权队列和堆的一些知识,对以前学过的东西有了进一步的认识,也认识到以前学习上的疏漏和不足,算法的时间复杂度是O(n^2)。
本来设计中没有考虑终点可变的情形,后来通过对output.h中输出函数的修改,加入一个变量k,对函数进行相应的修改不断地调试,最终得到正确的结果,本次实验对编程能力尤其是调试和改进程序的能力有了较大的提高。