A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx
- 文档编号:19254171
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:32
- 大小:239.45KB
A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx
《A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx(32页珍藏版)》请在冰豆网上搜索。
结点在closed表中,将closed表中结点加入Bestnode后继结点链,若此结点g值小于closed表中结点g值,closed表中结点改变parent指针,closed表中结点重新加入open表中,并删除此点
open表和closed表中均无此点,将此点加入Bestnode后继结点链,并按一定规则的加入到open表中
【问题描述】
在一个3*3的方棋盘上放着1,2,3,4,5,6,7,8八个数码,每个数码各占一格,且有一个空格。
这些数码可以在棋盘上移动,其移动规则时:
与空格相邻的数码放个可以移入空格。
现在的问题是:
对于指定的初始棋局和目标棋局,给出数码的移动序列。
【核心代码】
while(!
isEmpty(open)){
•//从open表中拿出f值最小的元素,并将拿出的元素放入closed表中
•popN(open,tmpNode);
•addN(closed,tmpNode);
•outputS(tmpNode);
•if(HValue(tmpNode)==0)success=true;
//目标结点
•SucceedL(tmpNode,succeed);
//后继存入succeed
•//判断后继结点
•while(!
isEmpty(succeed)){
•popN(succeed,tmpLNode);
•if(inLink(tmpLNode,open,tmpChartNode,thePreNode))
•elseif(inLink(tmpLNode,closed,tmpChartNode,thePreNode))
•else{
•addSucceedN(tmpNode,tmpLNode);
•addAscNode(open,tmpLNode);
•}
•
•if(success)outputBR(tmpNode);
//打印最优路径
}
【实验结果】
1.启发式函数h(n)采用不在位奖牌数时,所得结果:
2.启发式函数h(n)采用曼哈顿距离时的结果
对比上述两种情况,因此实验中,不在位奖牌数为4,曼哈顿距离为1+2+1+1=5.所以但启发式函数采用曼哈顿距离时,其包含的启发信息量大,搜索效率高。
体现在上实验上便是,加入open表的状态数少1.但最终最优路径一致。
【实验思考】
八数码的可解问题
如上图,此种情况下,八数码问题是无解的。
通过查阅资料,了解到八数码解的问题可以通过逆序数的奇偶性来判断。
因为八数码问题在空白移动过程中,数码的逆序数不改变。
左右移动,数码序列不变。
上下移动,数码序列中某个数字则移动了两位,整个序列的奇偶性不变。
问题的实质就是:
如果是N*N的数码盘的话,左右移动,数码序列不变;
上下移动则数码序列变动N-1位。
若N为奇数则在变动过程中其逆序数的奇偶性不会改变。
因八数码问题N=3,为奇数
故可通过判断当前状态S的逆序数以及目标状态SD的数字序列的逆序数的奇偶性是否相同来判断该问题是否可解。
模拟退火算法作为局部搜索算法的一种扩展,是根据复杂组合优化问题与固体的退火过程之间的相似之处,从而在它们之间建立联系而提出来的。
它是一种典型的概率模拟算法,其基本思想时在一个相当大的空间内搜索最优解,而每次只搜索与自己临近的状态,并按照Metropolis准则随机地接受一些劣解,及指标函数值大的解,当温度比较高时,接受劣解的概率比较大,在初始温度下,几乎以100%的概率接受劣解。
随着温度的下降,接受劣解的概率逐渐减小,直到当温度趋于0时,接受劣解的概率也趋于0。
这样将有利于算法从局部最优解中跳出,求得问题的全局最优解。
•选择初始状态S(初始解)、初始温度、降温次数
•生成S的邻域状态S‘,并计算C(S’)-C(S)
•按接收概率置换S
•重复第二步直至停机条件
假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路经的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。
路径的选择目标是要求得的路径路程为所有路径之中的最小值。
while(true){
•for(i=0;
i<
IN_LOOP;
i++){
newPath=getnext(curPath);
//交换任意两点,产生新路径
delta=newPath.length-curPath.length;
if(delta<
0)//更新长度
•{curPath=newPath;
P_L=0;
P_F=0;
Else{
•p=(double)(1.0*rand()/(RAND_MAX+1.0));
•if(exp(delta/T)<
1&
&
exp(delta/T)>
p)
–{curPath=newPath;
•P_L++;
if(P_L>
LIMIT){P_F++;
break;
}}//Endfor
•if(curPath.length<
newPath.length){D_BestPath=curPath;
•if(P_F>
FINL_LOOP||T<
FINNAL_T)break;
•T=T*RATE;
实验采用27个城市的坐标作为实验数据。
算法中的初始温度T=100,温度衰减率RATE=0.95,内循环次数IN_LOOP=15000
而当初始温度T取1000,温度衰减率和内循环次数均不变时
可以看出,温度的升高并没有带来路径长度的减小,而且其最优路径也不一致,所以模拟退火算法的参数设置是一大关键问题。
在实验中,无意发现初始温度这一参数的改变,并没有使算法达到课本中提到的,从理论上讲当初始温度足够高,状态交换足够充分,温度下降足够缓慢,最终温度足够低时,退火过程将达到最小能量的状态,所以通过查阅相关文献,发现在模拟退火算法解决TSP问题时,确实存在参数的设置问题,而且其相互之间存在一定的约束关系。
[1]闫利军,李宗斌,卫军胡.模拟退火算法的一种参数设定方法研究.系统仿真学报.2008.20
(1):
245~247
其中,采用序列优化的巢分割算法对模拟退火算法解决TSP问题的参数进行了评测,并与单纯的巢分割算法对该问题评测的结果进行了对比。
所以本次试验参数的选取变选择了初始温度T=100,温度衰减率RATE=0.95,内循环次数IN_LOOP=15000
文章中并没有之处其表格最后一列平均性能具体指什么,但其反复强调在文章中提出的算法比NP(巢分割)算法能有效地减少迭代次数,加快收敛,所以在此推测,其平均性能指收敛的时间。
[2]刘洪普,侯向丹.模拟退火算法中关键参数的研究.计算机工程与科学.2008.30(10):
55~57
此文是对每个参数选取了3个经验值,并固定其二,评测另外一个的方法来进行参数的研究。
附录
【A*算法解决八数码问题代码】
#include"
stdafx.h"
iostream"
stdlib.h"
conio.h"
#definesize3
usingnamespacestd;
//定义二维数组来存储数据表示某一个特定状态
typedefintstatus[size][size];
structSucceedL;
//定义状态图中的结点数据结构
typedefstructNode
{
statusdata;
//结点所存储的状态
structNode*parent;
//指向结点的父亲结点
structSucceedL*child;
//指向结点的后继结点
structNode*next;
//指向open或者closed表中的后一个结点
intfvalue;
//结点的总的路径
intgvalue;
//结点的实际路径
inthvalue;
//结点的到达目标的苦难程度
}NNode,*PNode;
//定义存储指向结点后继结点的指针的地址
typedefstructSucceedL
structNode*pointData;
//指向结点的指针
structSucceedL*next;
//指向兄第结点
}SPLink,*PSPLink;
PNodeopen;
PNodeclosed;
//开始状态与目标状态
statusstartt={2,8,3,1,6,4,7,0,5};
statustarget={1,2,3,8,0,4,7,6,5};
//初始化一个空链表
voidinitLink(PNode&
Head)
Head=(PNode)malloc(sizeof(NNode));
Head->
next=NULL;
//判断链表是否为空
boolisEmpty(PNodeHead)
if(Head->
next==NULL)
returntrue;
else
returnfalse;
//从链表中拿出一个数据
voidpopN(PNode&
Head,PNode&
FNode)
if(isEmpty(Head))
{
FNode=NULL;
return;
}
FNode=Head->
next;
next=Head->
next->
FNode->
//向结点的最终后继结点链表中添加新的子结点
voidaddSucceedN(PNode&
Head,PNodenewData)
PSPLinknewNode=(PSPLink)malloc(sizeof(SPLink));
newNode->
pointData=newData;
child;
child=newNode;
//释放状态图中存放结点后继结点地址的空间
voidfreeSpringLink(PSPLink&
PSPLinktmm;
while(Head!
=NULL)
tmm=Head;
Head=Head->
free(tmm);
//释放open表与closed表中的资源
voidfreeLink(PNode&
PNodetmn;
tmn=Head;
Head=Head->
free(tmn);
//首先释放存放结点后继结点地址的空间
freeSpringLink(Head->
child);
tmn=Head;
free(tmn);
//向普通链表中添加一个结点
voidaddN(PNode&
newNode)
next=newNode;
//向非递减排列的链表中添加一个结点
voidaddAscNode(PNode&
PNodeP;
PNodeQ;
P=Head->
Q=Head;
while(P!
=NULL&
P->
fvalue<
fvalue)
Q=P;
P=P->
//上面判断好位置之后,下面就是简单的插入了
next=Q->
Q->
//计算结点额h值
intHValue(PNodetheNode)
intnum=0;
/*for(inti=0;
i<
3;
i++)
for(intj=0;
j<
j++)
{
if(theNode->
data[i][j]!
=target[i][j])
num++;
}
}*/
for(inti=0;
i<
3;
i++)
for(intj=0;
j<
j++)
for(intk=0;
k<
k++)
{
for(intl=0;
l<
l++)
{
if(theNode->
data[i][j]==target[k][l])
num+=abs(i-k)+abs(j-l);
}
}
returnnum;
//计算结点的f,g,h值
voidcomputeAllValue(PNode&
theNode,PNodeparentNode)
if(parentNode==NULL)
theNode->
gvalue=0;
gvalue=parentNode->
gvalue+1;
theNode->
hvalue=HValue(theNode);
fvalue=theNode->
gvalue+theNode->
hvalue;
//初始化函数,进行算法初始条件的设置
voidinitial()
//初始化open以及closed表
initLink(open);
initLink(closed);
//初始化起始结点,令初始结点的父节点为空结点
PNodeNULLNode=NULL;
PNodeStart=(PNode)malloc(sizeof(NNode));
for(inti=0;
Start->
data[i][j]=startt[i][j];
Start->
parent=NULL;
child=NULL;
computeAllValue(Start,NULLNode);
//起始结点进入open表
addAscNode(open,Start);
//将B节点的状态赋值给A结点
voidstatusAEB(PNode&
ANode,PNodeBNode)
ANode->
data[i][j]=BNode->
data[i][j];
//两个结点是否有相同的状态
boolhasSameStatus(PNodeANode,PNodeBNode)
if(ANode->
=BNode->
data[i][j])
returnfalse;
returntrue;
//结点与其祖先结点是否有相同的状态
boolhasAnceSameStatus(PNodeOrigiNode,PNodeAnceNode)
while(AnceNode!
if(hasSameStatus(OrigiNode,AnceNode))
returntrue;
AnceNode=AnceNode->
parent;
returnfalse;
//取得方格中空的格子的位置
voidgetPosition(PNodetheNode,int&
row,int&
col)
data[i][j]==0)
row=i;
col=j;
return;
//交换两个数字的值
voidchangeAB(int&
A,int&
B)
intC;
C=B;
B=A;
A=C;
//检查相应的状态是否在某一个链表中
boolinLink(PNodespciNode,PNodetheLink,PNode&
theNodeLink,PNode&
preNode)
preNode=theLink;
theLink=theLink->
while(theLink!
if(hasSameStatus(spciNode,theLink))
theNodeLink=theLink;
preNode=theLink;
theLink=theLink->
//产生结点的后继结点(与祖先状态不同)链表
voidSucceedL(PNodetheNode,PNode&
succeed)
introw;
intcol;
getPosition(theNode,row,col);
//空的格子右边的格子向左移动
if(col!
=2)
PNoderlNewNode=(PNode)malloc(sizeof(NNode));
statusAEB(rlNewNode,theNode);
changeAB(rlNewNode->
data[row][col],rlNewNode->
data[row][col+1]);
if(hasAnceSameStatus(rlNewNode,theNode->
parent))
free(rlNewNode);
//与父辈相同,丢弃本结点
else
rlNewNode->
parent=theNode;
computeAllValue(rlNewNode,theNode);
//将本结点加入后继结点链表
addN(succeed,rlNewNode);
//空的格子左边的格子向右移动
=0)
PNodelrNewNode=(PNode)malloc(sizeof(NNode));
statusAEB(lrNewNode,theNode);
changeAB(lrNewNode->
data[row][col],lrNewNode->
data[row][col-1]);
if(hasAnceSameStatus(lrNewNode,theNode->
free(lrNewNode);
lrNewNode->
computeAllValue(lrNewNode,theNode);
addN(succeed,lrNewNode);
//空的格子上边的格子向下移动
if(row!
PNodeudNewNode=(PNode)malloc(sizeof(NNode));
statusAEB(udNewNode,theNode);
changeAB(udNewNode->
data[row][col],udNewNode->
data[row-1][col]);
if(hasAnceSameStatus(udNewNode,theNode->
free(udNewNode);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 数码 问题 SA 模拟 退火 旅行