人工智能实验报告包括八数码问题八皇后问题和tsp问题.docx
- 文档编号:24341740
- 上传时间:2023-05-26
- 格式:DOCX
- 页数:36
- 大小:55.39KB
人工智能实验报告包括八数码问题八皇后问题和tsp问题.docx
《人工智能实验报告包括八数码问题八皇后问题和tsp问题.docx》由会员分享,可在线阅读,更多相关《人工智能实验报告包括八数码问题八皇后问题和tsp问题.docx(36页珍藏版)》请在冰豆网上搜索。
人工智能实验报告包括八数码问题八皇后问题和tsp问题
人工智能实验报告,包括八数码问题八皇后问题和tsp问题
八数码问题
(一)问题描述
在一个3*3的方棋盘上放置着1,2,3,4,5,6,7,8八个数码,每个数码占一格,且有一个空格。
这些数码可以在棋盘上移动,其移动规则是:
与空格相邻的数码方格可以移入空格。
现在的问题是:
对于指定的初始棋局和目标棋局,给出数码的移动序列。
该问题称八数码难题或者重排九宫问题。
(二)问题分析
八数码问题是个典型的状态图搜索问题。
搜索方式有两种基本的方式,即树式搜索和线式搜索。
搜索策略大体有盲目搜索和启发式搜索两大类。
盲目搜索就是无“向导”的搜索,启发式搜索就是有“向导”的搜索。
1、启发式搜索
由于时间和空间资源的限制,穷举法只能解决一些状态空间很小的简单问题,而对于那些大状态空间的问题,穷举法就不能胜任,往往会导致“组合爆炸”。
所以引入启发式搜索策略。
启发式搜索就是利用启发性信息进行制导的搜索。
它有利于快速找到问题的解。
由八数码问题的部分状态图可以看出,从初始节点开始,在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零。
所以,这个数码不同的位置个数便是标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息就可以指导搜索。
即可以利用启发信息来扩展节点的选择,减少搜索范围,提高搜索速度。
启发函数设定。
对于八数码问题,可以利用棋局差距作为一个度量。
搜索过程中,差距会逐渐减少,最终为零,为零即搜索完成,得到目标棋局。
(三)数据结构与算法设计
该搜索为一个搜索树。
为了简化问题,搜索树节点设计如下:
structChess//棋盘
{
intcell[N][N];//数码数组
intValue;//评估值
DirectionBelockDirec;//所屏蔽方向
structChess*Parent;//父节点
};
intcell[N][N];数码数组:
记录棋局数码摆放状态。
intValue;评估值:
记录与目标棋局差距的度量值。
DirectionBelockDirec;所屏蔽方向:
一个屏蔽方向,防止回推。
Direction:
enumDirection{None,Up,Down,Left,Right};//方向枚
举
structChess*Parent;父节点:
指向父亲节点。
下一步可以通过启发搜索算法构造搜索树。
1、局部搜索树样例:
2、搜索过程
搜索采用广度搜索方式,利用待处理队列辅助,逐层搜索(跳过劣质节点)。
搜索
过程如下:
(1)、把原棋盘压入队列;
(2)、从棋盘取出一个节点;
(3)、判断棋盘估价值,为零则表示搜索完成,退出搜索;
(4)、扩展子节点,即从上下左右四个方向移动棋盘,生成相应子棋盘;(5)、对子节点作评估,是否为优越节点(子节点估价值小于或等于父节点则为优越
节点),是则把子棋盘压入队列,否则抛弃;
(5)、跳到步骤
(2);
3、算法的评价
完全能解决简单的八数码问题,但对于复杂的八数码问题还是无能为力。
现存在的一些优缺点。
1、可以改变数码规模(N),来扩展成N*N的棋盘,即扩展为N数码问题的求解过程。
--[if!
supportLists]-->2、
--[endif]-->内存泄漏。
由于采用倒链表的搜索树结
构,简化了数据结构,但有部分被抛弃节点的内存没有很好的处理,所以会造成内存
泄漏;
--[if!
supportLists]-->3、
--[endif]-->采用了屏蔽方向,有效防止往回搜索(节
点的回推),但没能有效防止循环搜索,所以不能应用于复杂度较大的八数码问题;
源码:
#include"stdio.h"
#include"stdlib.h"
#include"time.h"
#include"string.h"
#include
#include
usingnamespacestd;
constintN=3;//3*3棋盘
constintMax_Step=30;//最大搜索深度
enumDirection{None,Up,Down,Left,Right};//方向
structChess//棋盘
{
intcell[N][N];//数码数组
intValue;//评估值
DirectionBelockDirec;//所屏蔽方向
structChess*Parent;//父节点
};
//打印棋盘
voidPrintChess(structChess*TheChess){
printf("------------------------------------------------------------------------\n");
for(inti=0;i { printf("\t"); for(intj=0;j { printf("%d\t",TheChess->cell[i][j]); } printf("\n"); } printf("\t\t\t\t差距: %d\n",TheChess->Value); } //移动棋盘 structChess*MoveChess(structChess*TheChess,DirectionDirect,boolCreateNewChess) { structChess*NewChess; //获取空闲格位置 inti,j; for(i=0;i { boolHasGetBlankCell=false; for(j=0;j { if(TheChess->cell[i][j]==0) { HasGetBlankCell=true; break; } } if(HasGetBlankCell) break; } //移动数字 intt_i=i,t_j=j; boolAbleMove=true; switch(Direct) { caseUp: t_i++; if(t_i>=N) AbleMove=false; break; caseDown: t_i--; if(t_i<0) AbleMove=false; break; caseLeft: t_j++; if(t_j>=N) AbleMove=false; break; caseRight: t_j--; if(t_j<0) AbleMove=false; break; }; if(! AbleMove)//不可以移动则返回原节点 { returnTheChess; } if(CreateNewChess) { NewChess=newChess(); for(intx=0;x { for(inty=0;y NewChess->cell[x][y]=TheChess->cell[x][y]; } } else NewChess=TheChess; NewChess->cell[i][j]=NewChess->cell[t_i][t_j]; NewChess->cell[t_i][t_j]=0; returnNewChess; } //初始化一个初始棋盘 structChess*RandomChess(conststructChess*TheChess) { intM=30;//随机移动棋盘步数 structChess*NewChess; NewChess=newChess(); memcpy(NewChess,TheChess,sizeof(Chess)); srand((unsigned)time(NULL)); for(inti=0;i { intDirect=rand()%4; //printf("%d\n",Direct); NewChess=MoveChess(NewChess,(Direction)Direct,false); } returnNewChess; } //估价函数 intAppraisal(structChess*TheChess,structChess*Target) { intValue=0; for(inti=0;i { for(intj=0;j { if(TheChess->cell[i][j]! =Target->cell[i][j]) Value++; } } TheChess->Value=Value; returnValue; } //搜索函数 structChess*Search(structChess*Begin,structChess*Target) { Chess*p1,*p2,*p; intStep=0;//深度 p=NULL; queue Queue1.push(Begin); //搜索 do{ p1=(structChess*)Queue1.front(); Queue1.pop(); for(inti=1;i<=4;i++)//分别从四个方向推导出新子节点 { DirectionDirect=(Direction)i; if(Direct==p1->BelockDirec)//跳过屏蔽方向 continue; p2=MoveChess(p1,Direct,true);//移动数码 if(p2! =p1)//数码是否可以移动 { Appraisal(p2,Target);//对新节点估价 if(p2->Value<=p1->Value)//是否为优越节点 { p2->Parent=p1; switch(Direct)//设置屏蔽方向,防止往回推 { caseUp: p2->BelockDirec=Down;break; caseDown: p2->BelockDirec=Up;break; caseLeft: p2->BelockDirec=Right;break; caseRight: p2->BelockDirec=Left;break; } Queue1.push(p2);//存储节点到待处理队列 if(p2->Value==0)//为0则,搜索完成 { p=p2; i=5; } } else { deletep2;//为劣质节点则抛弃 p2=NULL; } } } Step++; if(Step>Max_Step) returnNULL; }while(p==NULL||Queue1.size()<=0); returnp; } main() { Chess*Begin,Target,*T; //设定目标棋盘[012],[345],[678] for(inti=0;i { for(intj=0;j { Target.cell[i][j]=i*N+j; } } //获取初始棋盘 Begin=RandomChess(&Target); Appraisal(Begin,&Target); Begin->Parent=NULL; Begin->BelockDirec=None; Target.Value=0; printf("目标棋盘: \n"); PrintChess(&Target); printf("初始棋盘: \n"); PrintChess(Begin); //图搜索 T=Search(Begin,&Target); //打印 if(T) { /*把路径倒序*/ Chess*p=T; stack while(p->Parent! =NULL) { Stack1.push(p); p=p->Parent; } printf("搜索结果: \n"); while(! Stack1.empty()) { PrintChess(Stack1.top()); Stack1.pop(); } printf("\n完成! "); }else printf("搜索不到结果.深度为%d\n",Max_Step); scanf("%d",T); } 八皇后问题 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。 该问题是十九世纪著名的数学家高斯1850年提出: 在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 基本思想: 在open表中保留已生成而未考察的结点,并用启发函数h(x)对它们全部进行估价,从中选出最优结点进行扩展,而不管这个结点出现在搜索树的什么地方。 (1)把初始结点S0放入open表中,计算h(S0); (2)若open表为空,则搜索失败,EXIT; (3)移出open表中第一个结点N放入closed表中,并冠以序号n (4)若目标结点Sg=N则搜索成功,EXIT (5)若N不可扩展,则转步骤 (2); (6)扩展N,计算每个子结点x的函数值h(x),并将所有子结点配以指向N的返回指针后放入open表中,再对open表中的所有子结点按其函数值大小以升序排序,转步骤2; //采用启发式修补解N皇后问题 #include #include //采用启发式修补解N皇后问题 #include #include using...namespacestd; voidshuffle(intQueen[],constintn)...{//随机取得各行的初始皇后位置,以Queen[i]表示第i行的皇后位置 for(inti=0;i Queen[i]=abs(rand())%n; } intcollision(intQueen[],constintrow,constintcolumn,constintn) ...{//计算每个位置的冲突值 intbug=0; for(inti=0;i ...{ if((i! =row)&&(Queen[i]==column||(Queen[i]-column)==(i-row) ||(Queen[i]-column)==(row-i)))//同列,同对角线的情况 bug; } returnbug; } voidshow(intQueen[],constintn) ...{//打印皇后图 cout<<"? "; for(intk=0;k cout<<"? ? "; cout<<"? ? "< for(inti=0;i ...{ cout<<"? "; for(intj=0;j cout<<((j==Queen[i])? "凤": "")<<"? ";//有皇后的位置用"凤" cout< cout<<"? "; for(j=0;j cout<<"? ? "; cout<<"? ? "< } cout<<"? "; for(intj=0;j cout<<((j==Queen[n-1])? "凤": "")<<"? ";//有皇后的位置用,没有的用_ cout< cout<<"? "; for(k=0;k cout<<"? ? "; cout<<"? ? "< cout< } intrepair(intQueen[],constintn) ...{//启发式修补 intmax=-1;//标志行行之间冲突数 intminbug=n; intcount=0; while(max! =0&&count<=100) ...{ max=0; for(inti=0;i ...{ minbug=collision(Queen,i,Queen[i],n);//取得当前的冲突数,不断优化 inttemp=Queen[i]; for(intj=0;j ...{ intbug=collision(Queen,i,j,n); if(bug<=minbug&&j! =temp) ...{//保持皇后在等冲突的情况下不断变更位置,有利于后面行的优化 minbug=bug; Queen[i]=j; } } if(minbug>max) max=minbug; } show(Queen,n); count; } returncount; } voidmain() ...{ intn=-1; intstep=0; cout<<"WelcometoNQueenSettlement"< cout<<"InputN(youwouldbetterinputaintergeminorto15): "< cin>>n; if(n<=0) ...{ cout<<"IllegalInput! "< return; } int*Queen=newint[n]; srand(time(NULL));//取得随机种子 shuffle(Queen,n); cout<<"Theoringinalstate: "< show(Queen,n); step=repair(Queen,n); if(step>100) ...{ cout<<"Couldfindsolutionwithin100steps,Tryagain! "< return; } cout<<"After"< cout<<"Thegoalstatearrives! "< 汉诺塔问题 遗传算法求TSP问题 遗传算法(GeneticAlgorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法,它最初由美国Michigan大学J.Holland教授于1975年首先提出来的,并出版了颇有影响的专著《AdaptationinNaturalandArtificialSystems》,GA这个名称才逐渐 为人所知,J.Holland教授所提出的GA通常为简单遗传算法(SGA)。 遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体(individual)组成。 每个个体实际上是染色体(chromosome)带有特征的实体。 染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。 因此,在一开始需要实现从表现型到基因型的映射即编码工作。 由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(geneticoperators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。 这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。 遗传算法特点 遗传算法是一类可用于复杂系统优化的具有鲁棒性的搜索算法,与传统的优化算法相比,主要有以下特点: 1、遗传算法以决策变量的编码作为运算对象。 传统的优化算法往往直接决策变量的实际值本身,而遗传算法处理决策变量的某种编码形式,使得我们可以借鉴生物 学中的染色体和基因的概念,可以模仿自然界生物的遗传和进化机理,也使得我们能够方便的应用遗传操作算子。 2、遗传算法直接以适应度作为搜索信息,无需导数等其它辅助信息。 3、遗传算法使用多个点的搜索信息,具有隐含并行性。 4、遗传算法使用概率搜索技术,而非确定性规则。 /*********************************************************************** *遗传算法解决TSP问题* *codeby小白atJuly.30* ***********************************************************************/ def.h ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, #ifndef_GENERATION_AMOUNT #define_GENERATION_AMOUNT201//每一代的生存数 #define_CITY_AMOUNT10//城市数,等于基因数 //#define_XCHG_GENE_AMOUNT_WHEN_MIX2//每次杂交所交换的碱基数量 #define_TIMES50//定义进化次数 #define_DISP_INTERVAL5//每隔多少次显示基因中的最高适应度 #define_CONTAINERstd: : vector #define_CONTAINER_Pstd: : vector #define_P(a,x,y)*(a+(x)+(y)*_CITY_AMOUNT) #define_P_GENE_ABERRANCE10//变异概率1% #define_P_GENE_MIX(_GENE
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 人工智能 实验 报告 包括 数码 问题 皇后 tsp