TSP问题的解决与实现报告Word文件下载.docx
- 文档编号:22414501
- 上传时间:2023-02-04
- 格式:DOCX
- 页数:34
- 大小:28.15KB
TSP问题的解决与实现报告Word文件下载.docx
《TSP问题的解决与实现报告Word文件下载.docx》由会员分享,可在线阅读,更多相关《TSP问题的解决与实现报告Word文件下载.docx(34页珍藏版)》请在冰豆网上搜索。
点n的值为5;
接下来程序输出提示信息—“Pleaseinsertthedistancebetweenonecityand
”,例如用户输入测试数据中给出的路程矩阵,表示任意两个城市之间的距离,比another:
如第一个城市到第0个城市之间的距离为25。
(3)
用户输入数据完毕,程序将输出运算结果。
(4)测试数据均为正数,其中用999来表示两个城市之间距离为∞。
3.概要设计
为了实现上述程序功能,使用优先队列来维护结点表,因此需要图和队列两个抽象数据类型。
(1)图的抽象数据类型定义
ADTGraph{
Data:
具有相同类型的数据元素的集合,称为顶点集。
:
Relation顶点偶对的有穷集合。
Operation
CreateGraph(&
G,V,VR)
初始条件:
是图中顶点集合,是图中顶点偶对集合。
VRV
操作条件:
按照和的定义构造图。
VGVR
DestroyGraph(&
G)
图已经存在。
G
操作结果:
销毁。
LocateVex(G,u)
图已经存在,和中顶点有相同类型。
uGG
如果中存在则返回在中的位置;
否则返回相应信息。
Guu,G
GetVex(G,v)
图已经存在,是中某个顶点。
vGG
返回的值。
v
PutVex(&
G,v,value)
图已经存在,是中顶点。
GGv
对赋值。
vvalue
FirstAdjvex(G,v)
vGG
返回的第一个邻接顶点。
如果在中没有邻接顶点,则返回相应信息。
vvG
NextAdjvex(G,v,w)
图已经存在,是中顶点是的邻接顶点。
GvG,wv
返回的下一个邻接顶点。
如果是的最后一个邻接点,则返回相应信息。
vwv
InsertVex(&
G,v,w)
图已经存在,和是中顶点。
GwvG
在中添加。
vG
DeleteVex(&
G,v)
GGv
删除中顶点及其相关的边。
Gv,v,w)
InsertEdge(&
G.
wGGv
在中添加;
如果是无向图,则还增添。
GG<
w,v>
<
v,w>
DeleteEdge(&
在中删除如果是无向图,则还删除。
;
<
DFSTraverse(G,v)
从起深度访问。
Gv
BFSTraverse(G,v)
从起广度访问。
}ADTGraph
(2)队列的抽象数据类型
ADTQueue{
具有相同数据类型的及先进先出特性的数据元素集合。
Relation
相邻数据元素具有前驱和后继的关系。
InitQueue(&
Q)
无
创造一个空队列。
Q
DestroyQueue(&
队列已经存在。
ClearQueue(&
重置为空队列。
QueueLength(Q)
返回的元素个数。
,&
e)
GetHead(Q初始条件:
队列已经存在并且非空。
用返回的队头元素。
eQEnQueue(&
Q,e)
DeQueue(&
Q初始条件:
队列已经存在且非空。
删除的队头元素,并用返回其值。
eQ
}ADTQueue
(3)本程序包含三大模块:
主程序模块,TSP算法模块,辅函数模块。
三大模块之间的调用关系如下。
主函数模块
算法模块TSP
辅函数模块
.详细设计4元素类型、结点类型和指针类型、变量和数据结构声明
(1)
父亲结点指针//Node*xnode;
//儿子结点指针Node*ynode;
儿子结点指针//Node*znode;
优先队列首指针//Node*qbase;
当前可行解的最优值//;
boundElemType
typedefintElemType;
//元素类型
#defineMAX_VALUE_OF_TYPE999;
//代表∞
城市顶点用数字0,1,2,……,n-1编号。
在搜索的过程中,各个结点的数据是动态变化的,互不相同,发生回溯时,必须使用结点中原来的数据。
因此,每个结点的数据必须是局部与该结点的。
用如下的数据结构来定义结点中所使用的数据:
typedefstructNode{
ElemTypec[100][100];
//路程矩阵
intinit_row[100];
//路程矩阵的当前行映射为原始行
intinit_col[100];
//路程矩阵的当前列映射为原始列
intcur_row[100];
//路程矩阵的原始行映射为当前行
intcur_col[100];
//路程矩阵的原始列映射为当前列
intad[100];
//回路顶点邻接表
intk;
//当前路程矩阵的阶
ElemTypew;
//结点的下界
structNode*next;
//队列链指针
}Node;
(2)队列类型
typedefstructQNode{
Node*data;
//数据域
structQNode*next;
//指针域
}QNode,*QueuePtr;
typedefstruct{
QueuePtrfront;
//头指针,指向链队头结点
QueuePtrrear;
//尾指针,指向链队列最后一个结点
}LinkQueue;
程序中所用到的关于优先队列基本操作实现的伪码算法如下:
voidInitQueue(LinkQueue&
Q){
//构造一个空链队列Q
Q.front=Q.rear=newQNode;
Q.front->
next=NULL;
}//InitQueue
voidEnQueue(LinkQueue&
Q,Node*e){
//插入一个指针e到链队列Q中,成为新的队尾指针
QueuePtrp;
p=newQNode;
p->
data=e;
Q.rear->
next=p;
Q.rear=p;
}//EnQueue
Node*DeQueue(LinkQueue&
//若链队列Q为空,则返回NULL;
否则返回指向数据的指针
QNode*p;
Node*e;
if(Q.front->
next==NULL)returnNULL;
p=Q.front->
next;
e=p->
data;
Q.front->
next=p->
if(Q.rear==p)Q.rear=Q.front;
deletep;
returne;
}//DeQueue
(3)辅助函数的实现(共7个)
ElemTypeRow_min(Node*node,introw,ElemType&
second){
//计算路程矩阵行的最小值
if(node->
c[row][0]<
node->
c[row][1]){
temp=node->
c[row][0];
second=node->
c[row][1];
}
else{
second=node->
for(i=2;
i<
k;
i++){
c[row][i]<
temp){
second=temp;
c[row][i];
elseif(node->
second)
returntemp;
ElemTypeCol_min(Node*node,intcol,ElemType&
//计算路程矩阵列的最小值
c[0][col]<
c[1][col]){
c[0][col];
c[1][col];
c[i][col]<
c[i][col];
ElemTypeArray_red(Node*node){
//归约node所指向的结点的路程矩阵
sum=0;
for(i=0;
i++){//行归约
temp=Row_min(node,i,temp1);
//行归约常数
for(j=0;
j<
j++)
node->
c[i][j]-=temp;
sum+=temp;
//行归约常数累计
for(j=0;
j++){//列归约
temp=Col_min(node,j,temp1);
//列归约常数
i++)
returnsum;
ElemTypeEdge_sel(Node*node,int&
vk,intv1){
//计算D,选择搜索分支的边kld=0;
ElemType*row_value=newElemType[node->
k];
ElemType*col_value=newElemType[node->
i++)//每一行的次小值
Row_min(node,i,row_value[i]);
for(i=0;
i++)//每一列的次小值
Col_min(node,i,col_value[i]);
i++){//对路程矩阵所有的0元素值
j++){//计算相应的temp值
c[i][j]==0){
temp=row_value[i]+col_value[i];
if(temp>
d){//求最大的temp值于d
d=temp;
vk=i;
v1=j;
}//保存相应的行、列号
deleterow_value;
deletecol_value;
returnd;
voidDel_rowcol(Node*node,intvk,intv1){
//删除路程矩阵的第vk行和第v1列的所有元素
for(i=vk;
k-1;
i++)//元素上移
v1;
c[i][j]=node->
c[i+1][j];
for(j=v1;
j++)//元素左移
vk;
c[i][j+1];
//元素上移及左移for(i=vk;
for(j=v1;
c[i+1][j+1];
vk1//当前行转换为原始行vk1=node->
init_row[vk];
//原始行vk1置删除标志node->
row_cur[vk1]=-1;
之后的原始行,其对应的当前行号减1//vk1for(i=vk1+1;
n;
row_cur[i]--;
//当前列v1转换为原始列vl1vl1=node->
init_col[v1];
置删除标志//原始列vl1node->
col_cur[vl1]=-1;
1//vl1之后的原始列,其对应的当前列号减for(i=vl1+1;
col_cur--;
i++)修改//vk及其后的当前行的对应原始行号
init_row[i]=node->
init_row[i+1];
修改//v1及其后的当前列的对应原始行号for(i=v1;
init_col[i]=node->
init_col[i+1];
1//当前矩阵的阶数减node->
k--;
voidEdge_byp(Node*node,intvk,intvl){
//登记回路顶点邻接表,旁路有关的边//当前行号转换为原始行号vk=init_row[vk];
vl=init_col[vl];
当前列号转换为原始列号//
登记回路顶点邻接表//node->
ad[vk]=vl;
k=node->
row_cur[vl];
//vl转换为当前行号k
l=node->
col_cur[vk];
//vk转换为当前列号l
if((k>
=0)&
&
(l>
=0))//当前行、列号均处于当前矩阵中
c[k][l]=MAX_VALUE_OF_TYPE;
//旁路相应的边
Node*Initial(ElemTypec[][],intn){
//初始化
Node*node=newNode;
//分配结点缓冲区
i++)//复制路程矩阵的初始数据
c[i][j]=c[i][j];
i++){//建立路程矩阵原始行、列号与初始行、列号对应的关系
init_row[i]=i;
init_col[i]=i;
row_cur=i;
col_cur=i;
i++)//回路顶点邻接表初始化为空
ad[i]=-1;
k=n;
returnnode;
//返回结点指针
(4)TSP问题分支限界算法
voidTSP(ElemTypec[100][100],intn,int*ad){
bound=MAX_VALUE_OF_TYPE;
InitQueue(qbase);
//初始化队列
xnode=Initial(c,n);
//初始化父亲结点--------x结点
xnode->
w=Array_red(xnode);
//归约路程矩阵
while(xnode->
k!
=0){
d=Edge_sel(xnode,vk,vl);
//选择分支方向并计算Dkl
znode=newNode;
//建立分支结点------z结点(右儿子结点)
结点z结点数据复制给//x*znode=*xnode;
znode->
c[vk][vl]=MAX_VALUE_OF_TYPE;
//旁路结点的边
Array_red(znode);
//归约z结点路程矩阵
w=xnode->
w+d;
//计算z结点的下界
if(znode->
w<
bound)//若下界小于当前可行解最优值
EnQueue(qbase,znode);
//将z结点插入优先队列
elsedeleteznode;
//否则,剪去该结点
ynode=newNode;
//建立分支节点----y结点(左儿子结点)
*ynode=*xnode;
//x结点数据复制到y结点
Edge_byp(ynode,vk,vl);
//登记回路邻接表,旁路有关的边
Del_rowcol(ynode,vk,vl);
//删除结点y路程矩阵当前vk行vl列
ynode->
//归约y结点路程矩阵
w+=xnode->
w;
//计算y结点的下界
if(ynode->
k==2){//路程矩阵只剩2阶
if((ynode->
c[0][0]==0)&
(ynode->
c[1][1]==0)){
ad[ynode->
init_row[0]]=ynode->
init_col[0];
init_row[1]]=ynode->
init_col[1];
}//登记最后的两条边
ynode->
k=0;
bound){//若下界小于当前可行解最优值
EnQueue(qbase,ynode);
//y结点插入优先队列
if(ynode->
k==0)//更新当前可行解最优值
bound=ynode->
elsedeleteynode;
//否则剪去y结点
xnode=DeQueue(qbase);
//取优先队列首元素
//保存最短路线长度
i++)//保存路线的顶点邻接表
ad[i]=xnode->
ad[i];
deletexnode;
//释放x结点缓冲区
释放队列节点缓冲区//while(qbase.front!
=qbase.rear){
xnode=DeQueue(qbase);
deletexnode;
cout<
Thewayis:
for(intm=0;
m<
m++)
ad[m];
endl;
cout<
Thelengthofthewayis:
(5)主函数的伪码算法
voidmain(){
”Pleaseinsertthenumberofcities:
”;
cin>
>
”Pleaseinsertthedistancebetweenonecityandanother:
{cin>
c[i][j];
””;
TSP(c,n,ad);
}//main
(6)函数调用关系图
main
TSP
EnQueue
Initial
Array_red
Edge_sel
Edge_byp
DeQueueInitQueue
Del_rowcol
Row_min
5.调试分析
(1)
使用分支限界法求解的过程中,将动态地生成很多结点,用结点表来存放动态生成的结点信息。
因此必须按路
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- TSP 问题 解决 实现 报告