广州大学学生实验报告
开课学院及实验室: 计算机科学与网络工程学院电子信息楼513 2023年11月26日
学院 | 计算机科学与网络工程学院 | 年级/专业/班 | ****** | 姓名 | **** | 学号 | **** |
实验课程名称 | 人工智能原理实验 | 成绩 | |||||
实验项目名称 | 实验一 谓词的表示与知识推理实验 | 指导老师 | **** |
实验一 谓词的表示与知识推理实验
- 实验目的
本实验课程是计算机、智能、物联网等专业学生的一门专业课程,通过实验,帮助学生更好地掌握人工智能相关概念、技术、原理、应用等;通过实验提高学生编写实验报告、总结实验结果的能力;使学生对智能程序、智能算法等有比较深入的认识。本实验通过不同知识的表达与推理问题,强化学生对知识表示的了解和应用,为人工智能后续环节的课程奠定基础。
二、基本要求
- 实验前,复习《人工智能原理》课程中的有关内容。
- 准备好实验数据。
- 编程或验证需要独立完成,程序应加适当的注释。
- 完成实验报告。
三、实验软件
使用C或C++(Visual studio平台等),或其它语言,如matlab或Python。
四、实验内容:
- 猴子摘香蕉问题
利用一阶谓词逻辑求解猴子摘香蕉问题:房内有一个猴子,一个箱子,天花板上挂了一串香蕉,其位置如图1所示,猴子为了拿到香蕉,它必须把箱子搬到香蕉下面,然后再爬到箱子上。请定义必要的谓词,列出问题的初始化状态(即下图所示状态),目标状态(猴子拿到了香蕉,站在箱子上,箱子位于位置b)。(附加:从初始状态到目标状态的谓词演算过程。)
图1
定义描述环境状态的谓词。
AT(x,w):x在w处,个体域:x?{monkey},w?{a,b,c,box};
HOLD(x,t):x手中拿着t,个体域:t?{box,banana};
EMPTY(x):x手中是空的;
ON(t,y):t在y处,个体域:y?{b,c,ceiling};
CLEAR(y):y上是空的;
BOX(u):u是箱子,个体域:u?{box};
BANANA(v):v是香蕉,个体域:v?{banana};
使用谓词、连结词、量词来表示环境状态。
问题的初始状态可表示为:So:AT(monkey,a)?EMPTY(monkey)?ON(box,c)?ON(banana,ceiling)?CLEAR(b)?BOX(box)?
BANANA(banana)
要达到的目标状态为:Sg:
AT(monkey,box)?HOLD(monkey,banana)?ON(box,b)?CLEAR(ceiling)?CLEAR(c)?
BOX(box)?BANANA(banana)
从初始状态到目标状态的转化, 猴子需要完成一系列操作, 定义操作类谓词表示其动作。
WALK(m,n):猴子从m走到n处,个体域:m,n?{a,b,c};
CARRY(s,r):猴子在r处拿到s,个体域:r?{c,ceiling},s?{box,banana};
CLIMB(u,b):猴子在b处爬上u;
这3个操作也可分别用条件和动作来表示。条件直接用谓词公式表示,是为完成相应操作所必须具备的条件;当条件中的事实使其均为真时,则可激活操作规则,于是可执行该规则中的动作部分。动作通过前后状态的变化表示,即通过从动作前删除或增加谓词公式来描述动作后的状态。
WALK(m,n):猴子从m走到n处
条件:AT(monkey,m)
动作:
CARRY(s,r):猴子在r处拿到s
条件:AT(monkey,r)?EMPTY(monkey)?ON(s,r)?BOX(box)?BANANA(banana)
动作:
CLIMB(u,b):猴子在b处爬上u
条件:AT(monkey,b)?HOLD(monkey,u)?CLEAR(b)?BOX(box)?BANANA(banana)
动作:
按照行动计划, 一步步进行状态替换, 直至目标状态
AT(monkey,a)?EMPTY(monkey)?ON(box,c)?ON(banana,ceiling)?CLEAR(b)?BOX(box)?
BANANA(banana)
AT(monkey,c)?EMPTY(monkey)?ON(box,c)?ON(banana,ceiling)?CLEAR(b)?BOX(box)?
BANANA(banana)
AT(monkey,c)?HOLD(monkey,box)?ON(banana,ceiling)?CLEAR(b)?CLEAR(c)?BOX(box)?
BANANA(banana)
AT(monkey,b)?HOLD(monkey,box)?ON(banana,ceiling)?CLEAR(b)?CLEAR(c)?BOX(box)?
BANANA(banana)
AT(monkey,box)?EMPTY(monkey)?ON(box,b)?ON(banana,ceiling)?CLEAR(c)?BOX(box)?
BANANA(banana)
AT(monkey,box)?HOLD(monkey,banana)?ON(box,b)?CLEAR(ceiling)?CLEAR(c)?BOX(box)?
BANANA(banana)(目标得解)
猴子行动的规则序列是:WALK(a,c)→CARRY(c,box)→WALK(c,b)→CLIMB(box,b)→
CARRY(banana,ceiling)
参考代码:
#include <stdio.h>
struct State
{
int monkey; /*-1:Monkey at A;0: Monkey at B;1:Monkey at C;*/
int box; /*-1:box at A;0:box at B;1:box at C;*/
int banana; /*Banana at B,Banana=0*/
int monbox; /*-1: monkey on the box;1: monkey the box;*/
};
struct State States [150];
char* routesave[150];
/*function monkeygoto,it makes the monkey goto the other place*/
void monkeygoto(int b,int i)
{
int a;
a=b;
if (a==-1)
{
routesave[i]="Monkey go to A";
States[i+1]=States[i];
States[i+1].monkey=-1;
}
else if(a==0)
{
routesave[i]="Monkey go to B";
States[i+1]=States[i];
States[i+1].monkey=0;
}
else if(a==1)
{
routesave[i]="Monkey go to C";
States[i+1]=States[i];
States[i+1].monkey=1;
}
else
{
printf("parameter is wrong");
}
}
/*end function monkeyygoto*/
/*function movebox,the monkey move the box to the other place*/
void movebox(int a,int i)
{
int B;
B=a;
if(B==-1)
{
routesave[i]="monkey move box to A";
States[i+1]=States[i];
States[i+1].monkey=-1;
States[i+1].box=-1;
}
else if(B==0)
{
routesave[i] = "monkey move box to B";
States[i+1]=States[i];
States[i+1].monkey=0;
States[i+1].box=0;
}
else if(B==1)
{
routesave[i] = "monkey move box to C";
States[i+1]=States[i];
States[i+1].monkey=1;
States[i+1].box=1;
}
else
{
printf("parameter is wrong");
}
}
/*end function movebox*/
/*function climbonto,the monkey climb onto the box*/
void climbonto(int i)
{
routesave[i]="Monkey climb onto the box";
States[i+1]=States[i];
States[i+1].monbox=1;
}
/*function climbdown,monkey climb down from the box*/
void climbdown(int i)
{
routesave[i]="Monkey climb down from the box";
States[i+1]=States[i];
States[i+1].monbox=-1;
}
/*function reach,if the monkey,box,and banana are at the same place,the monkey reach banana*/
void reach(int i)
{
routesave[i]="Monkey reach the banana";
}
/*output the solution to the problem*/
void showSolution(int i)
{
int c;
printf ("%s \n", "Result to problem:");
for(c=0; c<i+1; c++)
{
printf ("Step %d : %s \n",c+1,routesave[c]);
}
printf("\n");
}
/*perform next step*/
void nextStep(int i)
{
int c;
int j;
if(i>=150)
{
printf("%s \n", "steplength reached 150,have problem ");
return;
}
for (c=0; c<i; c++) /*if the current state is same to previous,retrospect*/
{
if(States[c].monkey==States[i].monkey&&States[c].box==States[i].box&&States[c].banana==States[i].banana&&States[c].monbox==States[i].monbox)
{
return;
}
}
if(States[i].monbox==1&&States[i].monkey==0&&States[i].banana==0&&States[i].box==0)
{
showSolution(i);
printf("Press any key to continue \n");
getchar();/*to save screen for user,press any key to continue*/
return;
}
j=i+1;
if(States[i].monkey==0)
{
if(States[i].box==0)
{
if(States[i].monbox==-1)
{
climbonto(i);
reach(i+1);
nextStep(j);
/*monkeygoto(-1,i);
nextStep(j);
monkeygoto(0,i);
nextStep(j);
movebox(-1,i);
nextStep(j);
movebox(0,i);
nextStep(j);*/
}
else
{
reach(i+1);
nextStep(j);
/*climbdown(i);
nextStep(j);*/
}
}
else if(States[i].box==1)
{
/*monkeygoto(-1,i);
nextStep(j);*/
monkeygoto(1,i);
nextStep(j);
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
else /*box==-1*/
{
monkeygoto(-1,i);
nextStep(j);
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
}
/*end if*/
if(States[i].monkey==-1)
{
if(States[i].box==-1)
{
if(States[i].monbox==-1)
{
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
else
{
climbdown(i);
nextStep(j);
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
}
else if(States[i].box==0)
{
monkeygoto(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
else
{
monkeygoto(1,i);
nextStep(j);
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
}
/*end if*/
if(States[i].monkey==1)
{
if (States[i].box==1)
{
if(States[i].monbox==-1)
{
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
else
{
climbdown(i);
nextStep(j);
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
}
else if(States[i].box==-1)
{
monkeygoto(-1,i);
nextStep(j);
movebox(0,i);
nextStep(j);
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
else
{
monkeygoto(0,i);
nextStep(j);
movebox(0,i);
nextStep(j);
climbonto(i);
reach(i+1);
nextStep(j);
}
}
/*end if*/
}/*end nextStep*/
int main()
{
States[0].monkey=-1;
States[0].box=1;
States[0].banana=0;
States[0].monbox=-1;
nextStep(0);
}
- 传教士(牧师)与野人问题
问题描述:
有n个牧师和n个野人准备渡河,但只有一条能容纳c个人的小船,为了防止野人侵犯牧师,要求无论在何处,牧师的人数不得少于野人的人数(除非牧师人数为0),且假定野人与牧师都会划船,试设计一个算法,确定他们能否渡过河去,若能,则给出小船来回次数最少的最佳方案。
实验步骤:
输入:牧师人数(即野人人数):n;小船一次最多载人量:c。
输出:若问题无解,则显示Failed,否则,显示Successed输出所有可行方案,并标注哪一组是最佳方案。用三元组(X1, X2, X3)表示渡河过程中的状态。并用箭头连接相邻状态以表示迁移过程:初始状态->中间状态->目标状态。
例:当输入n=2,c=2时,输出:221->200->211->010->021->000;
其中:X1表示起始岸上的牧师人数;X2表示起始岸上的野人人数;X3表示小船现在位置(1表示起始岸,0表示目的岸)。
要求:写出算法的设计思想和源程序,并有用户界面实现人机交互(控制台或者窗口都可以),进行输入和输出结果,如:
Please input n: 2 Please input c: 2
Optimal Procedure: 221->200->211->010->021->000
Successed or Failed?: Successed
3汉诺塔问题
汉诺塔问题来自一个古老的传说:在世界刚被创建的时候有一座钻石宝塔(塔A),其上有64个金碟。所有碟子按从大到小的次序从塔底堆放至塔顶。紧挨着这座塔有另外两个钻石宝塔(塔B和塔C)。从世界创始之日起,婆罗门的牧师们就一直在试图把塔A上的碟子移动到塔C上去,其间借助于塔B的帮助。每次只能移动一个碟子,任何时候都不能把一个碟子放在比它小的碟子上面。当牧师们完成任务时,世界末日也就到了。
采用问题归约法把汉诺塔问题分成以下三个步骤实现:
- 将塔A上的n-1个碟子借助塔C先移到塔B上
- 把塔A上剩下的一个碟子移到塔C上
- 把n-1个碟子从塔B借助于塔A移到塔C上
实验要求:
1.让盘子数从2 开始到7进行实验,记录程序运行时间和递归调用次数。
2.画出盘子数n和运行时间t 、递归调用次数m的关系图,并进行分析
五、学生实验报告要求
-
- 对于猴子摘香蕉问题根据自己编写代码或者参考代码,用不同的初始状态测试代码,记录每种初始状态下的输出结果,并对每个结果进行解释。
- 完善猴子摘香蕉问题参考代码,参考代码中有什么问题?应该如何修改会更好。
- 传教士(牧师)与野人问题,写出状态表示的数据结构,还有每种解的状态迁移图示。
- 写出传教士(牧师)与野人问题的程序清单(语言不限)
- 实验结果讨论。
实验报告
一 猴子摘香蕉问题
- 对于猴子摘香蕉问题根据自己编写代码或者参考代码,用不同的初始状态测试代码,记录每种初始状态下的输出结果,并对每个结果进行解释。
分析1 : 初始的时候, 猴子在A, 箱子在C,
步骤 : 所以, 猴子移动到C, 把箱子移动到B, 爬上箱子, 拿到香蕉
分析2 : 初始的时候, 猴子在A, 箱子在B
步骤 : 猴子移动到B, 爬上箱子, 拿到香蕉
分析3 : 初始的时候猴子在A, 箱子在A
步骤 : 猴子将箱子移动到B, 爬上箱子, 就能拿到香蕉
分析4 : 初始的时候, 猴子在B, 箱子在C
步骤 : 猴子移动C, 把箱子移动到B, 猴子爬上箱子, 拿到香蕉
- 完善猴子摘香蕉问题参考代码,参考代码中有什么问题?应该如何修改会更好。
问题1 : 代码的逻辑错误
错误2 :
- 实验代码
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
struct State
{
int monkey; // -1: 猴子在A; 0: 猴子在B; 1: 猴子在C;
int box; // -1: 箱子在A; 0: 箱子在B; 1: 箱子在C;
int banana; // 香蕉在B, banana = 0
int monbox; // -1: 猴子在箱子上; 1: 猴子在箱子里;
};
struct State States[150];
char *routesave[150];
// 猴子移动函数,使猴子移到另一个位置
void monkeygoto(int b, int i)
{
int a;
a = b;
if (a == -1)
{
routesave[i] = "猴子移动到A";
States[i + 1] = States[i];
States[i + 1].monkey = -1;
}
else if (a == 0)
{
routesave[i] = "猴子移动到B";
States[i + 1] = States[i];
States[i + 1].monkey = 0;
}
else if (a == 1)
{
routesave[i] = "猴子移动到C";
States[i + 1] = States[i];
States[i + 1].monkey = 1;
}
else
{
printf("参数错误");
}
}
// 移动箱子函数,猴子将箱子移到另一个位置
void movebox(int a, int i)
{
int B;
B = a;
if (B == -1)
{
routesave[i] = "猴子将箱子移动到A";
States[i + 1] = States[i];
States[i + 1].monkey = -1;
States[i + 1].box = -1;
}
else if (B == 0)
{
routesave[i] = "猴子将箱子移动到B";
States[i + 1] = States[i];
States[i + 1].monkey = 0;
States[i + 1].box = 0;
}
else if (B == 1)
{
routesave[i] = "猴子将箱子移动到C";
States[i + 1] = States[i];
States[i + 1].monkey = 1;
States[i + 1].box = 1;
}
else
{
printf("参数错误");
}
}
// 爬上箱子函数,猴子爬上箱子
void climbonto(int i)
{
routesave[i] = "猴子爬上箱子";
States[i + 1] = States[i];
States[i + 1].monbox = 1;
}
// 从箱子上爬下函数,猴子从箱子上爬下
void climbdown(int i)
{
routesave[i] = "猴子从箱子上爬下";
States[i + 1] = States[i];
States[i + 1].monbox = -1;
}
// 达到目标函数,如果猴子、箱子和香蕉在同一位置,猴子达到香蕉
void reach(int i)
{
routesave[i] = "猴子达到香蕉";
}
// 输出问题的解决方案
void showSolution(int i)
{
int c;
printf("%s \n", "问题的解决方案:");
for (c = 0; c < i + 1; c++)
{
printf("步骤 %d : %s \n", c + 1, routesave[c]);
}
printf("\n");
}
// 执行下一步
void nextStep(int i)
{
int c;
int j;
if (i >= 150)
{
printf("%s \n", "步长达到150,存在问题");
return;
}
for (c = 0; c < i; c++) // 如果当前状态与前一状态相同,则回溯
{
if (States[c].monkey == States[i].monkey && States[c].box == States[i].box && States[c].banana == States[i].banana && States[c].monbox == States[i].monbox)
{
return;
}
}
if (States[i].monbox == 1 && States[i].monkey == 0 && States[i].banana == 0 && States[i].box == 0)
{
showSolution(i);
printf("按任意键继续 \n");
getchar(); // 为了保存用户屏幕,按任意键继续
return;
}
j = i + 1;
if (States[i].monkey == 0)
{
if (States[i].box == 0)
{
if (States[i].monbox == -1)
{
climbonto(i);
reach(i + 1);
nextStep(j);
}
else
{
reach(i + 1);
nextStep(j);
}
}
else if (States[i].box == 1)
{
monkeygoto(1, i);
nextStep(j);
// movebox(0, i);
// nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
else
{
monkeygoto(-1, i);
nextStep(j);
// movebox(0, i);
// nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
}
else if (States[i].monkey == -1)
{
if (States[i].box == -1)
{
if (States[i].monbox == -1)
{
movebox(0, i);
nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
else
{
climbdown(i);
nextStep(j);
// movebox(0, i);
// nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
}
else if (States[i].box == 0)
{
monkeygoto(0, i);
nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
else //第一步
{
monkeygoto(1, i);
nextStep(j);
// movebox(0, i);
// nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
}
else if (States[i].monkey == 1)
{
if (States[i].box == 1)
{
if (States[i].monbox == -1) //第二部
{
movebox(0, i);
nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
else
{
climbdown(i);
nextStep(j);
// movebox(0, i);
// nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
}
else if (States[i].box == -1)
{
monkeygoto(-1, i);
nextStep(j);
// movebox(0, i);
// nextStep(j);
// movebox(0, i);
// nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
else
{
monkeygoto(0, i);
nextStep(j);
// movebox(0, i);
// nextStep(j);
// climbonto(i);
// reach(i + 1);
// nextStep(j);
}
}
}
int main()
{
States[0].monkey = -1;
States[0].box = 1;
States[0].banana = 0;
States[0].monbox = -1;
srand(time(0));
// States[0].monkey = rand() % 3 - 1; //取值范围 (-1, 1)
// States[0].box = rand() % 3 - 1; //取值范围 (-1, 1)
// States[0].banana = 0; //注意 : 香蕉的位置固定在B点
// States[0].monbox = -1;
printf("猴子在%c ", States[0].monkey + 'A' + 1);
printf("箱子在%c ", States[0].box + 'A' + 1);
printf("香蕉在%c\n", States[0].banana + 'A' + 1);
nextStep(0);
return 0;
}
二 传教士和野人问题
- 传教士(牧师)与野人问题,写出状态表示的数据结构,还有每种解的状态迁移图示。
struct State { int M; // 左岸传教士 int C; // 左岸野人 int side; // 船的位置 }; |
状态迁移图示
- 写出传教士(牧师)与野人问题的程序清单(语言不限)
程序清单 :
bool isRepeat() : 判断状态是否重复
boold isEnd() : : 判断是否已经成功过河
bool isValid() : 判断当前船的载人方案是否合法(使得传教士人数大于野人, 保证传教士的安全)
void dfs(int) : 递归函数 : 船载人过河
int main() : 主函数 : 调用dfs()进程过河载人方案的求解
- 实验运行结果
3个野人/传教士, 船载人数 : 2
结果 : 成功
2个野人/传教士, 船载人数 : 2
结果 : 成功
3个野人/传教士, 船载人数 : 3
结果 : 成功
3个野人/传教士, 船载人数 : 1
结果 : 失败
实验完整源代码 :
#include <iostream>
#include <vector>
#include <set>
#include <unordered_set>
using namespace std;
int mc = 3; // 传教士和野人的数目
int boat = 2; // 船承载的人数
bool success = false; // 成功求解?
// 岸的左边的状态
struct State
{
int M; // 传教士
int C; // 野人
int side; // 船的位置
// 无参构造函数
State()
{
}
// 有参构造函数
State(int m, int c, int side)
{
M = m;
C = c;
this->side = side;
}
};
vector<vector<State *>> ans; // 保存所有路径
// State *state = new State(mc, mc, 0); // 初始状态, 不能在这里初始化
State *state; // 初始状态
State *endState = new State(0, 0, 1); // 结束状态
vector<State *> path; // 保存路径
vector<State *> st; // 用于判断状态是否重复,
/**
* 状态是否重复
*/
bool isRepeat()
{
int n = st.size();
for (auto state2 : st)
{
if (state->M == state2->M && state->C == state2->C && state->side == state2->side)
{
return true;
}
}
return false;
}
// 结束状态判断
bool isEnd()
{
// cout << "isEnd : " << state->M << ' ' << state->C << " " << state->side << endl;
if (state->M == 0 && state->C == 0)
{
// 全部人移动到右边
return true;
}
return false;
}
/**
* 判断状态是否合法 :
* 1. M == C
* 2. M == 0
* 3. M == mc //
* 其他情况如果M > C, 那么另外一边就会出现 M < C, 所以都不合法
*
*/
bool isValid()
{
if (state->M == 0 || state->M == mc || state->M == state->C)
{
return true;
}
return false;
}
void dfs(int u)
{
// 递归结束
if (isEnd())
{
success = true;
cout << "步骤如下:\n";
ans.push_back(path);
for (int i = 0; i < path.size(); i++)
{
State *state2 = path[i];
cout << state2->M << state2->C << state2->side;
if (i != path.size() - 1)
cout << " -> ";
}
cout << endl;
return;
}
// 进行载人
// 船在左边
if (state->side == 0)
{
for (int i = 0; i <= boat && i <= state->M; i++) // 传教士的人数
{
for (int j = 0; j <= boat - i && j <= state->C; j++) // 野人的人数
{
if (i + j == 0)
continue; // 不能一个人也不在船
state->M -= i; // 人数减少
state->C -= j;
state->side = 1;
if (isValid() && !isRepeat())
{
// 保存路径
State *state2 = new State(state->M, state->C, state->side); // 要创建一个新的指针, 否则出错
path.push_back(state2);
st.push_back(state2);
dfs(u + 1);
path.pop_back(); // 弹出
st.pop_back();
}
// 恢复现场
state->M += i;
state->C += j;
state->side = 0;
}
}
}
// 船在右边, 左边的人数增加
else if (state->side == 1)
{
for (int i = 0; i <= boat && i <= mc - state->M; i++) // 传教士的人数
{
for (int j = 0; j <= boat - i && j <= mc - state->C; j++) // 野人的人数
{
if (i + j == 0)
continue; // 不能一个人也不在船
state->M += i; // 人数增加
state->C += j;
state->side = 0;
if (isValid() && !isRepeat())
{
State *state2 = new State(state->M, state->C, state->side);
path.push_back(state2); // 要创建一个新的指针, 否则出错
st.push_back(state2);
dfs(u + 1);
path.pop_back();
st.pop_back();
}
// 恢复现场
state->M -= i; // 人数增加
state->C -= j;
state->side = 1;
}
}
}
}
int main()
{
cout << "请输入传教士和野人的数目" << endl;
cin >> mc;
cout << "请输入小船最多载人量" << endl;
cin >> boat;
// 初始化
state = new State(mc, mc, 0); // 初始状态
State *state2 = new State(state->M, state->C, state->side); // 要创建一个新的指针, 否则出错
path.push_back(state2);
st.push_back(state2); // 第一个状态已经使用过了
dfs(0);
// 如果没有成功, 输出失败
if (!success)
{
cout << endl;
cout << "失败, 没有任何一个方案能够求解这个问题" << endl;
}
else
{
cout << endl;
cout << "succeed" << endl;
int n = ans.size();
int m = ans[0].size(); // 最优解的步数
for (int i = 1; i < n; i++)
{
if (ans[i].size() < m)
{
m = ans[i].size();
}
}
cout << "最好的方案是" << endl;
for (int i = 0; i < n; i++)
{
if (ans[i].size() == m)
{
auto best = ans[i];
for (int i = 0; i < m; i++)
{
cout << best[i]->M << best[i]->C << best[i]->side;
if (i != m - 1)
cout << " -> ";
}
cout << endl;
}
}
cout << endl;
}
return 0;
}
汉诺塔问题 :
- 让盘子数从2 开始到7进行实验,记录程序运行时间和递归调用次数
- 画出盘子数n和运行时间t 、递归调用次数m的关系图,并进行分析
分析 : 随机盘子的数目的增加, 运行时间的上升趋势越来越快
-
实验源代码
-
#include <iostream> #include <ctime> using namespace std; /** * 汉诺塔dfs函数 */ long long cnt = 0; //计数 void dfs(int u, char source, char target, char tool) { cnt ++; if(u == 1) { //将单个盘子, 直接移动到第三个柱子 cout << "将盘子1从" << source << "移动到" << target << endl; } else { dfs(u - 1, source, tool, target); //将上面的u - 1个盘子, A -> B, 借助 : C cout << "将盘子" << u << "从" << source << "移动到" << target << endl; dfs(u - 1, tool, target, source); } } int main() { int n = 7; cout << "盘子个数 : " << n << endl; clock_t st, ed; st = clock(); dfs(n, 'A', 'C', 'B'); ed = clock(); double time = (double)(ed - st) / CLOCKS_PER_SEC; cout << "递归次数 : " << cnt << endl; cout << "执行时间 : " << time << endl; }