A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx

上传人:b****5 文档编号:19254171 上传时间:2023-01-04 格式:DOCX 页数:32 大小:239.45KB
下载 相关 举报
A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx_第1页
第1页 / 共32页
A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx_第2页
第2页 / 共32页
A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx_第3页
第3页 / 共32页
A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx_第4页
第4页 / 共32页
A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx

《A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx(32页珍藏版)》请在冰豆网上搜索。

A星算法八数码问题和SA算法模拟退火算法旅行商问题Word文档下载推荐.docx

结点在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);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1