人工智能N皇后问题回溯法爬山算法的实现及性能分析.docx
《人工智能N皇后问题回溯法爬山算法的实现及性能分析.docx》由会员分享,可在线阅读,更多相关《人工智能N皇后问题回溯法爬山算法的实现及性能分析.docx(11页珍藏版)》请在冰豆网上搜索。
人工智能N皇后问题回溯法爬山算法的实现及性能分析
N皇后问题爬山法和回溯法的实现及性能
分析
云南大学信息学院
专业:
计算机软件与理论
一、N皇后问题3...
1.问题描述3
2.数据结构3
二、爬山算法3...
1.爬山算法一般介绍3
2.爬山算法的伪代码4
3.算法评价4
三、回溯法4...
1.回溯法一般介绍4
2.回溯法的伪代码4
3.算法评价5
四、算法实现及性能比较5...
五、两种算法性能分析6...
六、结论7
七、参考文献7...
附录8
一、N皇后问题
1.问题描述
(1)n皇后问题:
在n*n格的国际象棋上摆放n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,
(2)分别用回溯法(递归)、爬山法和GA算法求解n皇后问题。
要求:
输入n,并用运行时间比较几种算法在相同规模的问题时的求解效率。
列表给出结果。
2.数据结构
1、逻辑结构:
用到线性结构包括数组等。
2、存储结构(物理结构):
顺序存储结构。
二、爬山算法
1.爬山算法一般介绍
爬山法是指从当前的节点开始,和周围的邻居节点的值进行比较。
如果当前节点是最大的,那么返回当前节点,作为最大值(既山峰最高点);反之就用最高的邻居节点来,替换当前节点,从而实现向山峰的高处攀爬的目的。
如此循环直到达到最高点。
每次都选择是与目标结点启发函数值最小的那个结点,经过迂回前进,最终
达到解决问题的总目标。
如果我们把目标函数的几何图形看成一个山峰,那么点
的直接移动就像人在爬山,选择方向,逐步向山顶移动。
爬山法需要建立一个描述数据库变化的单极值函数,且使极值对应目标状态;选取使函数值增长最大的那条规则作用于数据库;重复上步,直到没有规则使函数值继续增长。
爬山法是一种局部搜索算法,也属一种启发式方法。
但它一般只能得到局部最优,并且这种解还依赖于起始点的选取。
它是一种解多变量无约束最优化问题的一类方法,通过点的直接移动产生的目标值有所改善的点,经过这样的移动,逐步到达使目标函数最优的点。
在爬山法中,h表示相互攻击的皇后的对数,用它来生成启发函数
2.爬山算法的伪代码
爬山函数(问题)是局部极大值的一种状态返回输入问题,一个问题局部变量:
当前,一个节点。
邻居,一个节点。
当前生成节点(初始状态[问题])
循环做
邻居一个价值最高当前的继任者
如果值[邻居]≤价值[当前],然后返回状态[当前]
当前邻居
3.算法评价
爬山法的缺点:
会出现山脊、高原,86%的时间会卡住;但是爬山算法较简单,在皇后的个数较多时体现出来效率最高,处理多约束大规模问题时往往不能得到较好的解。
三、回溯法
1.回溯法一般介绍
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。
但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。
2.回溯法的伪代码
回溯法基本思想是:
从一条路往前走,能进则进,不能进则退回来,换一条路再试。
对于n皇后问题,第一步按照顺序放一个皇后,然后第二步符合要求放第2个皇后,如果没有符合位置符合要求,那么就要改变第一个皇后的位置,重新放第2个皇后的位置,直到找到符合条件的位置就可以了,在目标状态终止。
3.算法评价
回溯法在皇后数目较小的,很占优势,它的速度非常的快,但随着皇后数目的增加,回溯法显得很不实用,在n=28时,用回溯法已不能较好的解决n皇后问题。
四、算法实现及性能比较
这里通过c++语言来实现各种排序算法(源码见附录),程序运行环境为windows7,所用编译器为vs2010。
实验分别以不同的皇后规模用例进行测试。
皇后规模设置为10,50,100,150,200,250实验部分结果如图4-1:
图4-1.部分测试结果
五、两种算法性能分析在测试中我们根据不同的皇后规模用例进行测试,并给出了各个规模的不同算法所用的运行时间(单位ms)。
表1为不同的皇后规模测试后得到的运行时间数据。
规模
时间
10
50
100
150
200
250
爬山法(ms)
42.0564
236.404
670.458
2481.45
6502.89
13210.3
回溯法(ms)
24.3441
436.536
1032.13
5624.18
8359.02
26567.6
表1不同的皇后规模运行时间(单位ms)
为了直观起见,根据实验数据画出不同的皇后规模以及不同算法的时间变化趋势图如图5-1所示:
图5-1两种算法用时变化趋势图
六、结论
爬山法是一种始终都比较快的算法,它的运行时间与皇后是个数没有必然的联系,而且在n很大时,它显现出来运行时间短,效率高的优势,但它的缺点是会出现山脊、高原,86%的时间会卡住。
总的来说,爬山算法较简单,也比较快,在皇后的个数较多时体现出来效率最高,处理多约束大规模问题时往往不能得到较好的解。
回溯法在皇后数目较小的,很占优势,它的速度非常的快,但随着皇后数目的增加,回溯法显得很不实用,在n=50时,用回溯法已不能较好的解决n皇后问题。
总的来说,回溯在n值很小时,效率最高,在n值很大时,回溯法不能再解决,此时,爬山法的效率最高,且与n值没有必然的联系。
七、参考文献
1.《Artificialintelligence:
;amodernapproach人工智能:
一种现代方法》作者:
Russell,StuartJ.出版社:
清华大学出版社
2.XX百科网站
附录
/*
*/
#include
#include
#include
#include
#include
#include
#include
usingnamespacestd;
typedefvectorCollisionList_t;
voidprint_row_mark(intN){
if(N>15)
{
return
}
for(inti=0;i}
cout<<"+"<voidprint_row(intN,intfill){
if(N>5)
{
return;
}
//cout<<"|";
for(inti=0;i/*if(i==fill)
cout<<"X";
else
)<<
cout<<"0";*/cout<<"|"<<((i==fill)
cout<<"|"<print_row_mark(N);
//皇后位置的表示方法:
//使用数组chessman[N]来表示N个皇后的位置
//第i个皇后chessman[i]的下标i表示其行所在的位置,//chessman[j]表示其列的位置。
//一个四皇后问题的表示方法如下所示:
//(0,1)(1,3)(2,0)(3,2)
//+---+---+---+---+
//||X|||
//+---+---+---+---+
//||||X|
//+---+---+---+---+
//|X||||
//+---+---+---+---+
//|||X||
//+---+---+---+---+
//
voidprint_chessboard(int*chessman,intN)
{
for(inti=0;iif(i%5==0)cout<<"\n";
cout<<"("<
print_row_mark(N);
for(intj=0;j}
}
//随机生成一个初始化状态,在每行每列上放置一个皇后voidgenerate_init_state(int*chessman,intN){
for(inti=0;i}
for(intj=0;jintr=rand();
r=r%N;
swap(chessman[r],chessman[N-r-1]);
//返回冲突的皇后个数
inth(int*chessman,intN,CollisionList_t&collision_list)
{collision_list.clear();
intcollision=0;
for(inti=0;ifor(introw=i+1;rowif((chessman[row]==chessman[i]+row-i)
||(chessman[row]==chessman[i]-(row-i))){collision_list.push_back(row);++collision;
}
}
}
returncollision;
}
//如果交换后冲突不比原来的大,就进行交换
//只有交换成功后才改变cl为新的冲突列表
inttry_exchange(int*chessman,intN,introw1,introw2,CollisionList_t&cl){
CollisionList_tnew_cl;
//交换两行的皇后的位置
swap(chessman[row1],chessman[row2]);
intnew_collision=h(chessman,N,new_cl);
if(new_collision>cl.size()){
//取消之前的交换
swap(chessman[row1],chessman[row2]);
}
else{
cl=new_cl;
}
returnnew_cl.size();
}
intchoose_next_state(int*chessman,intN,CollisionList_t&cl)
{
intold_collision=cl.size();intnew_collision;
introw1=-1;introw2=-1;
//优化最后只有一个冲突的解
if(cl.size()==1){
for(inti=0;iif(i!
=cl[0]&&(try_exchange(chessman,N,cl[0],i,cl)==0)){return0;
}
}