TSP问题算法分析.docx
- 文档编号:30059019
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:18
- 大小:66.52KB
TSP问题算法分析.docx
《TSP问题算法分析.docx》由会员分享,可在线阅读,更多相关《TSP问题算法分析.docx(18页珍藏版)》请在冰豆网上搜索。
TSP问题算法分析
算法第二次大作业
TSP问题算法分析
021251班
王昱(02125029)
1.问题描述
“TSP问题”常被称为“旅行商问题”,是指一名推销员要拜访多个地点时,如何找到在拜访每个地点一次后再回到起点的最短路径。
TSP问题在本实验中的具体化:
从A城市出发,到达每个城市并且一个城市只允许访问一次,最后又回到原来的城市,寻找一条最短距离的路径。
2.算法描述
2.1分支界限法
2.1.1算法思想
分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。
在分支限界法中,每一个活结点只有一次机会成为扩展结点。
活结点一旦成为扩展结点,就一次性产生其所有儿子结点。
在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。
这个过程一直持续到找到所需的解或活结点表为空时为止。
2.1.2算法设计说明
设求解最大化问题,解向量为X=(x1,…,xn),xi的取值范围为Si,|Si|=ri。
在使用分支限界搜索问题的解空间树时,先根据限界函数估算目标函数的界[down,up],然后从根结点出发,扩展根结点的r1个孩子结点,从而构成分量x1的r1种可能的取值方式。
对这r1个孩子结点分别估算可能的目标函数bound(x1),其含义:
以该结点为根的子树所有可能的取值不大于bound(x1),即:
bound(x1)≥bound(x1,x2)≥…≥bound(x1,…,xn)
若某孩子结点的目标函数值超出目标函数的下界,则将该孩子结点丢弃;否则,将该孩子结点保存在待处理结点表PT中。
再取PT表中目标函数极大值结点作为扩展的根结点,重复上述。
直到一个叶子结点时的可行解X=(x1,…,xn),及目标函数值bound(x1,…,xn)。
2.2A*算法
算法思想
对于某一已到达的现行状态,如已到达图中的n节点,它是否可能成为最佳路径上的一点的估价,应由估价函数f(n)值来决定。
假设g*(n)函数值表示从起始节点s到任意一个节点n的一条最佳路径上的实际耗散值。
h*(n)函数值表示从任意节点n到目标节点ti的最佳路径的实际耗散值。
其中ti是一个可能的目标节点。
f*(n)函数值表示从起始s,通过某一指定的n到达目标节点ti的一条最佳路径的实际耗散值,并有f*(n)=g*(n)+h*(n)。
假设f函数是对f*函数的一种估计,并有f(n)=g(n)+h(n),其中g函数是对g*的估计,h函数是对h*的一种估计。
f(n)包括两个部分,其中g(n)表示到达n节点时,已付出代价的估计;而h(n)表示从n节点到达目标节点ti将要付出代价的估计。
按f(n)=g*(n)+h*(n)的值来排序ff表的节点,f值小者优先。
通常称这种算法为A算法。
在A算法的基础上,进一步限制h(n)函数,使得搜索图中的每一个节点n,能满足h(n)<=h*(n)、称h函数取h*的下界。
这种算法叫A*算法。
对ff里的每一个节点做评估函数F分为两部分G和H:
假设从A城市走到X城市,又走到Y城市,所以G可表示为:
G=A到X的距离+X到Y的距离;
未走的的城市数=(总城市数+1)-目前城市的层数。
为什得加1,因为最后得走回初始城市,所以总路径的城市数为总城市数+1。
H=未走的城市数×目前的最小距离;
F=G+H;
计算ff表里每个节点的F值,F值最小的节点作为活路径,把它加到bestpath中。
3.算法代码
3.1分支界限法
#include
#include
#defineNoEdge1000
structMinHeapNode
{
intlcost;//子树费用的下界
intcc;//当前费用
intrcost;//x[s:
n-1]中顶点最小出边费用和
ints;//根节点到当前节点的路径为x[0:
s]
int*x;//需要进一步搜索的顶点是//x[s+1:
n-1]
structMinHeapNode*next;
};
intn;//图G的顶点数
int**a;//图G的邻接矩阵
//intNoEdge;//图G的无边标记
intcc;//当前费用
intbestc;//当前最小费用
MinHeapNode*head=0;/*堆头*/
MinHeapNode*lq=0;/*堆第一个元素*/
MinHeapNode*fq=0;/*堆最后一个元素*/
intDeleteMin(MinHeapNode*&E)
{
MinHeapNode*tmp=NULL;
tmp=fq;
//w=fq->weight;
E=fq;
if(E==NULL)
return0;
head->next=fq->next;/*一定不能丢了链表头*/
fq=fq->next;
//free(tmp);
return0;
}
intInsert(MinHeapNode*hn)
{
if(head->next==NULL)
{
head->next=hn;//将元素放入链表中
fq=lq=head->next;//一定要使元素放到链中
}else
{
MinHeapNode*tmp=NULL;
tmp=fq;
if(tmp->cc>hn->cc)
{
hn->next=tmp;
head->next=hn;
fq=head->next;/*链表只有一个元素的情况*/
}else
{
for(;tmp!
=NULL;)
{
if(tmp->next!
=NULL&&tmp->cc>hn->cc)
{
hn->next=tmp->next;
tmp->next=hn;
break;
}
tmp=tmp->next;
}
}
if(tmp==NULL)
{
lq->next=hn;
lq=lq->next;
}
}
return0;
}
intBBTSP(intv[])
{//解旅行售货员问题的优先队列式分支限界法
/*初始化最优队列的头结点*/
head=(MinHeapNode*)malloc(sizeof(MinHeapNode));
head->cc=0;
head->x=0;
head->lcost=0;
head->next=NULL;
head->rcost=0;
head->s=0;
int*MinOut=newint[n+1];/*定义定点i的最小出边费用*/
//计算MinOut[i]=顶点i的最小出边费用
intMinSum=0;//最小出边费用总合
for(inti=1;i<=n;i++)
{
intMin=NoEdge;/*定义当前最小值*/
for(intj=1;j<=n;j++)
if(a[i][j]!
=NoEdge&&/*当定点i,j之间存在回路时*/
(a[i][j] Min=a[i][j];/*更新当前最小值*/ if(Min==NoEdge) returnNoEdge;//无回路 MinOut[i]=Min; //printf("%d\n",MinOut[i]);/*顶点i的最小出边费用*/ MinSum+=Min; //printf("%d\n",MinSum);/*最小出边费用的总和*/ } MinHeapNode*E=0; E=(MinHeapNode*)malloc(sizeof(MinHeapNode)); E->x=newint[n]; //E.x=newint[n]; for(inti=0;i E->x[i]=i+1; E->s=0; E->cc=0; E->rcost=MinSum; E->next=0;//初始化当前扩展节点 intbestc=NoEdge;/*记录当前最小值*/ //搜索排列空间树 while(E->s {//非叶结点 if(E->s==n-2) {//当前扩展结点是叶结点的父结点 /* 首先考虑s=n-2的情形,此时当前扩展结点是排列树中某个叶结点的父结点。 如果该叶结点相应一条可行回路 且费用小于当前最小费用,则将该叶结点插入到优先队列中,否则舍去该叶结点 */ if(a[E->x[n-2]][E->x[n-1]]! =NoEdge&&/*当前要扩展和叶节点有边存在*/ a[E->x[n-1]][1]! =NoEdge&&/*当前页节点有回路*/ (E->cc+a[E->x[n-2]][E->x[n-1]]+a[E->x[n-1]][1] ||bestc==NoEdge)) { bestc=E->cc+a[E->x[n-2]][E->x[n-1]]+a[E->x[n-1]][1];/*更新当前最新费用*/ E->cc=bestc; E->lcost=bestc; E->s++; E->next=NULL; Insert(E);/*将该页节点插入到优先队列中*/ }else free(E->x);//该页节点不满足条件舍弃扩展结点 }else {/*产生当前扩展结点的儿子结点 当s 由于当前扩展结点所相应的路径是x[0: s], 其可行儿子结点是从剩余顶点x[s+1: n-1]中选取的顶点x[i],且(x[s],x[i])是所给有向图G中的一条边。 对于当前扩展结点的每一个可行儿子结点,计算出其前缀(x[0: s],x[i])的费用cc和相应的下界lcost。 当lcost */ for(inti=E->s+1;i if(a[E->x[E->s]][E->x[i]]! =NoEdge) {/*当前扩展节点到其他节点有边存在*/ //可行儿子结点 intcc=E->cc+a[E->x[E->s]][E->x[i]];/*加上节点i后当前节点路径*/ intrcost=E->rcost-MinOut[E->x[E->s]];/*剩余节点的和*/ intb=cc+rcost;//下界 if(b {//子树可能含最优解,结点插入最小堆 MinHeapNode*N; N=(MinHeapNode*)malloc(sizeof(MinHeapNode)); N->x=newint[n]; for(intj=0;j N->x[j]=E->x[j]; N->x[E->s+1]=E->x[i]; N->x[i]=E->x[E->s+1];/*添加当前路径*/ N->cc=cc;/*更新当前路径距离*/ N->s=E->s+1;/*更新当前节点*/ N->lcost=b;/*更新当前下界*/ N->rcost=rcost; N->next=NULL; Insert(N);/*将这个可行儿子结点插入到活结点优先队列中*/ } } free(E->x); }//完成结点扩展 DeleteMin(E);//取下一扩展结点 if(E==NULL) break;//堆已空 } if(bestc==NoEdge) returnNoEdge;//无回路 for(inti=0;i v[i+1]=E->x[i];//将最优解复制到v[1: n] while(true) {//释放最小堆中所有结点 free(E->x); DeleteMin(E); if(E==NULL) break; } returnbestc; } intmain() { n=0; inti=0; //FILE*in,*out; //in=fopen("input.txt","r"); //out=fopen("output.txt","w"); //if(in==NULL||out==NULL) //{ //printf("没有输入输出文件\n"); //return1; //} //fscanf(in,"%d",&n); n=5; a=(int**)malloc(sizeof(int*)*(n+1)); for(i=1;i<=n;i++) { a[i]=(int*)malloc(sizeof(int)*(n+1)); } //for(i=1;i<=n;i++) //for(intj=1;j<=n;j++) ////fscanf(in,"%d",&a[i][j]); //a[i][j]=1; a[1][1]=0; a[1][2]=6; a[1][3]=1; a[1][4]=5; a[1][5]=7; a[2][1]=6; a[2][2]=0; a[2][3]=6; a[2][4]=4; a[2][5]=3; a[3][1]=1; a[3][2]=6; a[3][3]=0; a[3][4]=8; a[3][5]=2; a[4][1]=5; a[4][2]=4; a[4][3]=8; a[4][4]=0; a[4][5]=5; a[5][1]=7; a[5][2]=3; a[5][3]=2; a[5][4]=5; a[5][5]=0; //prev=(int*)malloc(sizeof(int)*(n+1)); int*v=(int*)malloc(sizeof(int)*(n+1));//MaxLoading(w,c,n); for(i=1;i<=n;i++) v[i]=0; bestc=BBTSP(v); printf("\n"); printf("最优路径为"); for(i=1;i<=n;i++) fprintf(stdout,"%c\t",v[i]+64); fprintf(stdout,"\n"); fprintf(stdout,"总路程为\n",bestc); return0; } 3.2A*算法 #include"stdio.h" constintmax=9999; constintax=50; intisbest(inti,intbestpath[],intp)//检测改节点是否已经加入bestpath[]中 { for(intk=1;k<=p;k++) { if(i==bestpath[k]) break; } if(k! =p+1)//新测试节点在a[]中 return1; else return0; } voidmain() { intmin=max; intminf=max; intnum;//城市数量 intmat[ax][ax];//城市间距离 intbestpath[ax];//最佳路径 intf=0,g=0,h=0; intff[ax];//依次求每个城市的f值 intgg[ax];//城市的g值 printf("城市个数为: "); scanf("%d",&num); printf("城市间的距离为: \n");//输入各城市间距离的矩阵 for(inti=0;i for(intj=0;j scanf("%d",&mat[i][j]); bestpath[0]=0;//起点为0,即城市A for(intp=0;p { for(intkk=0;kk ff[kk]=max;//便于后面求最小值 for(i=1;i { if(isbest(i,bestpath,p))//该点已经在bestpath[]中的话,忽略 continue; else//计算该点的g值 gg[i]=g+mat[bestpath[p]][i];//i点的g值 for(intm=0;m { if(isbest(m,bestpath,p))//该点已经在bestpath[]中的话,忽略 continue; for(intt=m+1;t { if(isbest(t,bestpath,p)) continue; if(m! =0||t! =i||p==num-2)//不是最后一个点的话,不算A点到这个点长度 if(mat[m][t] min=mat[m][t]; } } h=min*(num-p-1);//h值 ff[i]=gg[i]+h;//第i个节点的f值 min=max;//重新赋值最大,以便下次循环 } for(i=0;i { if(ff[i] { minf=ff[i]; bestpath[p+1]=i; } } minf=max;//重新赋值最大,以便下次循环 g=g+mat[bestpath[p]][bestpath[p+1]];//更新g值 } printf("最优路径为: "); for(i=0;i printf("%c",bestpath[i]+65); printf("A\n"); printf("总路程为: "); intsum=0; for(i=0;i sum=sum+mat[bestpath[i]][bestpath[i+1]]; sum=sum+mat[bestpath[num-1]][0];//总路程最后一个城市要回到A,所以加上其距离 printf("%d\n",sum); } 4.结果截图 4.1分支界限法 4.2A*算法
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- TSP 问题 算法 分析