实验二.docx
《实验二.docx》由会员分享,可在线阅读,更多相关《实验二.docx(13页珍藏版)》请在冰豆网上搜索。
实验二
人工智能实验报告
\
学院:
信息工程学院
班级:
计研-14
学号:
笑嘻嘻笑嘻嘻
姓名:
笑嘻嘻笑嘻嘻
2014年11月
实验二梵塔问题实验
1.实验目的
(1)了解知识表示相关技术;
(2)掌握问题规约法或者状态空间法的分析方法。
2.实验内容
梵塔问题实验。
熟悉和掌握问题规约法的原理、实质和规约过程理解规约图的表示方法。
3.实验报告要求
(1)简述实验原理及方法,并请给出程序设计流程图。
对于有n个圆盘的汉诺塔问题,从x塔座移动至z塔座的方法为为:
如果只有一个圆盘,直接从x移至z,否则,演变成递归调用n-1个圆盘的汉诺塔问题,即将x塔座上面的n-1个圆盘从x移到y;然后把最下面的一个圆盘从x直接移到z;最后转换成递归调用n-1个圆盘的汉诺塔问题,再把y上临时存放的n-1个圆盘移到z塔座。
程序设计流程图:
(2)源程序清单:
#include
voidmove(chara,intn,charb){
printf("圆盘编号为%d%c移至%c\n",n,a,b);
}
voidhanoi(intn,charx,chary,charz){//将塔座x上编号为1至n的n个圆盘搬到z上
if(n==1)move(x,1,z);//将编号为1的圆盘从x移到z
else{
hanoi(n-1,x,z,y);//将x上编号为1至n-1个圆盘移到y,z作辅助塔
move(x,n,z);//将编号为n的圆盘从x移到z
hanoi(n-1,y,x,z);//将y上编号为1至n-1的圆盘移到z,x作辅助塔
}
}
voidmain(){
intn;
printf("请输入x塔上圆盘的数量:
");
scanf("%d",&n);
hanoi(n,'x','y','z');
}
}
(3)实验结果及分析。
心得体会:
通过梵塔问题的实验,我掌握了问题规约法的原理和实质,熟练运用了递归算法,充分认识了规约过程。
可以分析出本实验的时间复杂度为C(n)=
=
-1,这次实验报告的完成也增强了我对人工智能的学习积极性,和对语言的理解和应用能力。
实验二状态空间法实验
1.实验目的
(1)了解知识表示相关技术;
(2)掌握问题规约法或者状态空间法的分析方法。
2.实验内容
状态空间法实验。
从前有一条河,河的左岸有m个传教士、m个野人和一艘最多可乘n人的小船。
约定左岸,右岸和船上或者没有传教士,或者野人数量少于传教士,否则野人会把传教士吃掉。
搜索一条可使所有的野人和传教士安全渡到右岸的方案。
3.实验报告要求
(1)简述实验原理及方法,并请给出程序设计流程图。
实验原理:
初始状态是m个传教士、m个野人在河的左岸,现在用一个三元组(a,b,c)表示状态,其中a表示起始岸上传教士数目,b表示起始岸上野人数目,c表示小船位置,设定1代表在左岸,0代表在右岸。
可分为三种情况讨论:
当n>m/2时,先把所有的野人度过去,每次返回一个野人,当出现(m,0,0)情况时,返回m-n个野人(若m==n,返回1个野人)。
然后渡n个传教士,此时野人==传教士,然后返回一个野人和传教士。
由于河的左岸传教士与野人数目是(m-n+1)m/2,所有可以完全渡传教士,然后每次返回一个野人,最终直到a==b==c==0;
当n<=3&&n<=m/2||n==1,显然此时无解;
当n>=4&&n<=m/2,此时只能每次传n/2个传教士和野人,每次返回一个野人和传教士,直到最终结果。
流程图:
Y
N
(2)源程序清单:
#include"iostream"
usingnamespacestd;
boolflag=false;//标记是否有解
boolaf=false;//标记a是否为0
boolbf=false;//当b变为0后赋值为true;
boolef=false;//当a==b后赋值为true
boolf=false;//判断n是否大于m/2
intm;//传教士野人的个数
intn;//船一次能装载的人数
voidcrossing(inta,intb,intc);
intmain()
{
cout<<"请输入传教士与野人的个数:
\n";
cin>>m;
cout<<"请输入船一次能装载的人数:
\n";
cin>>n;
if((n<=3&&n<=m/2)||n==1)
{
cout<<"此种情况无解!
\n";
system("pause");
return0;//在main函数中,return0返回程序运行值到dos
}
cout<<"左岸传教士人数\t"<<"右岸野人个数\t"<<"船的位置"<if(n>m/2)
{
f=true;
}
crossing(m,m,1);
if(flag==true)
{
cout<<"成功渡河!
\n";
}
else
{
cout<<"无法渡河!
\n";
}
system("pause");
return0;
}
voidcrossing(inta,intb,intc)
{
if(flag==true)
{
return;
}
else
{
if(c==1)//船在左岸
{
cout<<"\t"<if(f==true)//n>m/2
{
if(bf!
=true)//b未达到过0b!
=0
{
if(a+b<=n)//如果a+b<=n,完全渡过
{
crossing(0,0,1-c);//递归
}
else
{
if(b>=n)//野人数大于或等于船的载量
{
crossing(a,b-n,1-c);//递归
if(flag==true)
return;
}
}
}
elseif(ef!
=true&&af==false)//b!
=0&&a!
=0
{
if(a>=n)
{
crossing(a-n,b,1-c);//递归
if(flag==true)
{
return;
}
}
}
if(ef==true&&af==false)//a==b&&a!
=0
{
if(a>=n)
{
crossing(a-n,b,1-c);//递归
}
//如果aelseif(a+b{
crossing(0,0,1-c);
}
else
{
crossing(0,b-n+a,1-c);
}
}
if(af==true)//a==0
{if(b>=n)
{
crossing(0,b-n,1-c);//递归
}
else
{
crossing(0,0,1-c);
}
}
}
else//n<=m/2
{
crossing(a-n/2,b-n/2,1-c);//递归
}
}
//船在左岸时,右岸的情况:
if(c==0)
{
cout<<"\t"<if(a==b&&b==c&&a==0)
{
flag=true;
return;
}
if(f==true)//如果n>m/2
{
if(b==0)
{
bf=true;
if(m<=n)
crossing(a,b+1,1-c);//递归
else
crossing(a,b+m-n,1-c);
}
if(a==b)
{
ef=true;
crossing(a+1,b+1,1-c);//递归
}
if(a==0)
{
af=true;
crossing(a,b+1,1-c);//递归
}
while(bf!
=true)
{
crossing(a,b+1,1-c);//递归
}
}
else//n<=m/2
crossing(a+1,b+1,1-c);//递归
}
}
}
(3)实验结果及分析
分析与心得:
通过本实验的练习,我更进一步了解状态空间法的应用原理,也对传教士野人问题有了深入的认识,同时对C++语言加以回顾与温习,学到更多的应用知识和方法,并通过这一实验的练习,及时弥补了忘却的一些知识点。
本程序的实验结果使用的是传教士与野人个数为3,船的负载能力为2,也可以输入其他数据,得到其相应结果,当输入的传教士与野人和船的负载能力不符合相关比例时,则显示无解,不能成功渡河。
这样的判断,可以减少程序运行的复杂度,采用递归的方法依次从河的左岸到右岸,分析河的左岸传教士与野人数目,这种算法比较简便,减少编程的工作量。
我从中提高了自己分析问题的能力,对算法的精简能力也得到了增强。