tsp.docx
- 文档编号:5634920
- 上传时间:2022-12-29
- 格式:DOCX
- 页数:12
- 大小:156.63KB
tsp.docx
《tsp.docx》由会员分享,可在线阅读,更多相关《tsp.docx(12页珍藏版)》请在冰豆网上搜索。
tsp
一、问题描述
旅行商问题,即TSP问题(TravellingSalesmanProblem)是指对给定一组n个城市和它们两两之间的直达距离,寻找一条闭合的旅程,使得每个城市刚好经过一次而且总的旅行距离最短。
此问题是典型NPC组合优化问题(NPC=Non-deterministicPolynomialcomplete,即是多项式复杂程度的非确定性完全问题。
)。
优化问题有三个基本要素:
变量、约束和目标函数。
在求解过程中,选定的基本参数称为变量;对变量取值的限制成为约束;表示可行方案衡量标准的函数成为目标函数。
二、问题分析与建模
TSP问题的数学描述为:
在一个边赋权的带权图中,寻找最小汉密尔顿回路。
对于N个城市的TSP问题,其城市的数目应为N。
若N个城市中,每两个城市之间都有连通的路径,其连通路径数目应为n*(n-1)/2。
而对于含有个顶点无向连接图来说,其完全图的边数也为n*(n-1)/2,因此可以用含有n个顶点的完全连通无向图来形象的描绘TSP问题的已知条件,而此完全连通无向图中每条边上的权值,可以表示TSP问题中每两个顶点之间的路径长度。
因此在其后的设计中,使用带权的完全无向连通图来分析TSP问题的求解过程。
一棵生成树是连通图的一个极小连通子图,它含有连通图中的全部n个顶点,一个连通图的最小生成树,是此图所有生成树中代价和最小的一棵生成树。
它与TSP问题所求路径有许多相同之处,它们都必须经过所有的n个顶点,n个顶点之间都是相互连通(但在TSP问题中,路径为回路),并且路径长度为最短。
因此,对于TSP问题的求解,可以借助于最小生成树的求解方法。
三、求解问题的算法
用最小生成树解决TSP问题。
构造最小生成树可以有多种,其中一种为普里姆(Prim)算法。
算法的描述为:
:
在含有n(n>1)个顶点的完全连通无向图中,任意选择一个顶点Vi作为起始点,在与顶点Vi相关联的n-1条边中,选择一条权值最小的边ei,此边可连接Vi及图中另一个顶点Vj,然后在与Vi或Vj相关联除ei以外的所有边中,选择权值最小的边ej,ej又可连接另外一个顶点(边的选则还要保证树中没有环的产生)。
依此求顶点的方法,依次求出所有的可连接n个顶点的n-1条边,因为在此生成树中的每一条边均为不会生成环的,且权值最小的连接顶点的边,因此这棵生成树为此含有n(n>1)个顶点的完全连通无向图的最小生成树。
搜索算法中应包括:
输入设计(城市数目;城市坐标;一个存储完全图的二维数组arry1[max][max](邻接矩阵,其中,max表示城市的数目,arry1[i][j]表示第i和第j个城市间的距离,例如下面的矩阵所示)。
);
路径查找设计(一个用于判断某个顶点是否已被选过的一维标志位数组arry2[max];一个用来存储查找的最短路径以及路径长度的二维数组arry3[max][max+2](array3[i][1]和array3[i][max]用来存储从第i个顶点出发的这条路径的起始点和始点array3[i][max+1]中存储的是这条闭合回路的路径长度。
)
V1V2V3V4V5V6
V1061500
V2605030
V3150564
V4505002
V5036006
V6004260
四、结果(运行时间均只需几秒)
1、10个随机城市的TSP
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
2、12个随机城市的TSP
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
3、30个随机城市的TSP(先将Max改为31)
.......................................................................................
五、程序
#include
#include
#include
#include
#defineMax21
intcn,tt,start;//要经过的城市个数,,起点
doublearry1[Max][Max];//邻接矩阵,存放两两城市间的距离
doublefn=0,gn=0,hn=0;//启发函数
doublef1=0,g1=0,h1=0;
intarry3[Max];//存放已历经的城市名
intarry4[Max];//标志位数组,cn个城市中已历经的置,未历经的置
//定义顶点数据类型
structVertex
{
intx;
inty;
}City[Max];
///////////////////////////////////////////////////////////////////////////////////////////
//主函数
voidmain()
{
voidRandNum(int);
voidCityCoordinate();
doubleCityCost(int,int);
voidTSP();
doubleMaxLengh();
inti,j;
CityCoordinate();//随机生成并显示个城市及其坐标
printf("\n");
printf("\n");
for(i=1;i { tt=0; for(j=i;j { if(i==j)arry1[i][j]=0; elsearry1[i][j]=CityCost(i,j); } } TSP();//用最小生成树查找最短路径 printf("\n从%d出发的最佳路径为: %d→",start,start); for(i=2;i<=cn;i++)printf("%d→",arry3[i]); printf("%d\n",arry3[cn+1]); printf("总路径长度为: %f\n",fn); } /////////////////////////////////////////////////////////////////////////////////////////// //随机数产生器 intRandNum(intmax) { intm; m=rand()%(max-1)+1;//产生一个~20的随机数 returnm; } //生成并显示城市坐标 voidCityCoordinate() { inti,j,hh=0; srand((unsigned)time(NULL));//使用当前时间作为种子 City[1].x=RandNum(Max);//生成并显示第个城市的坐标 City[1].y=RandNum(Max); printf("City[1]的坐标: (%d,%d);",City[1].x,City[1].y); for(i=2;i { City[i].x=RandNum(Max); City[i].y=RandNum(Max); for(j=1;j if(City[i].x==City[j].x&&City[i].y==City[j].y) i=i-1; hh++;//换行 if(0! =i%2)hh=0; if(0==hh)printf("\n"); printf("City[%d]的坐标: (%d,%d);",i,City[i].x,City[i].y);//显示第i个城市的坐标 } } //计算并显示城市间的欧式距离 doubleCityCost(inti,intj) { intx1,x2,y1,y2,hh=0; doubleDistance,t; x1=City[i].x; x2=City[j].x; y1=City[i].y; y2=City[j].y; t=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); Distance=sqrt(t); arry1[i][j]=Distance; hh++; if(0! =tt%2)hh=0;//换行 if(0==hh)printf("\n"); printf("%d与%d的距离: %3.2f",i,j,Distance); returnarry1[i][j]; } //用启发式的MST查找最短路径///////////////////////////////////////////////////////// voidTSP() { intMnode;//起点,当前搜索层的父节点 inth,i,k,l,m,n,nn; intx,y=0; intarry2[Max]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//标志位数组,已历经的置0,未历经的置1 doubletemp1=100,temp2=100; doublelayer1[Max];//初始化当前搜索层节点 doublelayer2[Max];//初始化后继搜索层节点 printf("\n请输入要经过的城市个数: "); scanf_s("%d",&cn); printf("\n"); printf("请输入要历经的城市: \n"); for(h=1;h<=cn;h++)//输入历经节点 { scanf_s("%d",&x); if(0==arry2[x])arry2[x]=1;//避免重复 elseif(1==arry2[x])h=h-1; } printf("\n"); for(i=1;i if(1==arry2[i]) printf("%d",i); printf("\n"); printf("请输入出发城市: ");//输入出发点 scanf_s("%d",&start); printf("\n"); arry2[start]=0;//初始化 arry3[1]=start; arry3[cn+1]=start; Mnode=arry3[1]; //////////////////////////////////////////////////////////////////////搜索路径 for(n=2;n<=cn;n++)//找出城市~cn { for(nn=1;nn { layer1[nn]=0; layer2[nn]=0; } for(k=1;k if(1==arry2[k]) { gn=g1+arry1[Mnode][k]; hn=arry1[k][start]; fn=gn+hn; layer1[k]=fn; } for(l=1;l if(0! =layer1[l]) { y=l; break; } for(m=y+1;m 。 。 。 。 。 。 。 。 。 。 。 。 。 比较并查找最佳后继 { if(layer1[y]==layer1[m])////////////////如果出现两个后继代价相同,搜索它们的下一层节点 { Mnode=y;//////先以y为父节点 arry2[y]=0; for(k=1;k if(1==arry2[k]) { gn=g1+arry1[Mnode][k]; hn=arry1[k][start]; fn=gn+hn; layer2[k]=fn; } for(l=1;l if(0! =layer2[l]&&temp1>layer2[l])temp1=layer2[l]; for(nn=1;nn Mnode=m;//////再以m为父节点 arry2[y]=1; arry2[m]=0; for(k=1;k if(1==arry2[k]) { gn=g1+arry1[Mnode][k]; hn=arry1[k][start]; fn=gn+hn; layer2[k]=fn; } for(l=1;l if(0! =layer2[l]&&temp2>layer2[l])temp2=layer2[l]; arry2[y]=1;arry2[m]=1;//消除假设条件下对arry2[]值的改变 if(temp1>temp2)y=m; } elseif(0! =layer1[m]&&layer1[y]>layer1[m])y=m; }//。 。 。 。 。 。 。 。 。 。 。 。 。 。 比较并查找最佳后继 g1=g1+arry1[Mnode][y]; Mnode=y; arry2[y]=0; arry3[n]=y; } fn=g1+arry1[y][start]; }/////////////////////////////////////////////////////////////搜索路径
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- tsp