用python编写猴子吃桃问题_上午给猴子四只香蕉

用python编写猴子吃桃问题_上午给猴子四只香蕉房内有一个猴子,一个箱子,天花板上挂了一串香蕉,其位置如图1所示,猴子为了拿到香蕉,它必须把箱子搬到香蕉下面,然后再爬到箱子上。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

一、猴子摘香蕉问题

1、问题描述

利用一阶谓词逻辑求解猴子摘香蕉问题:房内有一个猴子,一个箱子,天花板上挂了一串香蕉,其位置如图1所示,猴子为了拿到香蕉,它必须把箱子搬到香蕉下面,然后再爬到箱子上。请定义必要的谓词,列出问题的初始化状态(即下图所示状态),目标状态(猴子拿到了香蕉,站在箱子上,箱子位于位置b)。
(附加:从初始状态到目标状态的谓词演算过程。)
在这里插入图片描述

2、解题思路

猴子按照先到箱子所在位置/从箱子上爬下来→把箱子搬到香蕉下面→爬上箱子摘香蕉的逻辑进行着。
所以需要编写四个行动逻辑——走到箱子所在位置、从箱子上爬下来、把箱子搬到香蕉上面、爬上箱子摘香蕉。

使用一个结构定义猴子、箱子、香蕉、相对箱子的位置状态——
猴子在A点则标-1,猴子在B点则标0,猴子在C点则标1
箱子在A点则标-1,箱子在B点则标0,箱子在C点则标1
香蕉在A点则标-1,香蕉在B点则标0,香蕉在C点则标1
猴子爬上箱子则标1,没爬上则标-1

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];

输入一个初始状态(a, b, c, d)
根据问题,确定终止状态是猴子摘到香蕉{(x,x,x,0)}(x 属于 {0,-1, 1})。

使用递归调用的方式搜索路径,每次递归前先判断当前状态是否与之前的状态重复,若重复则认为形成一个环路,回到上一步寻找其他方式通往新的状态。

3、实验结果及分析

实验结果一

在这里插入图片描述
分析:
初始时,猴子站在A位置,箱子在C位置,香蕉在B位置,猴子没有站在箱子上。

猴子摘香蕉的步骤如下:
猴子走去C位置→猴子把箱子从C位置搬到B位置→猴子爬上箱子→猴子摘到香蕉

实验结果二

在这里插入图片描述
分析:
初始时,猴子站在A位置,箱子在B位置,香蕉在B位置,猴子没有站在箱子上。

猴子摘香蕉的步骤如下:
猴子走去B位置→猴子爬上箱子→猴子摘到香蕉

实验结果三

在这里插入图片描述
分析:
初始时,猴子站在A位置,箱子在A位置,香蕉在B位置,猴子站在箱子上。

猴子摘香蕉的步骤如下:
猴子从箱子上爬下来→猴子把箱子从A位置搬到B位置→猴子爬上箱子→猴子摘到香蕉

4、实验结果

当传教士与野人为五人,船最多允许三人过河时,程序运行结果如下
在这里插入图片描述
解的状态迁移图
1、550->441->440->331->330->221->220->111->110->001
在这里插入图片描述
2、550->441->440->331->330->221->220->011->110->001
在这里插入图片描述
3、550->441->540->331->330->221->220->111->110->001
在这里插入图片描述

4、550->441->540->331->330->221->220->011->110->001
在这里插入图片描述

5、实验代码

#include "stdafx.h"
#include<string.h>
#include<iostream>
#include <stdio.h>
using namespace std;

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);
		exit(0);
	}

	j = i + 1;//进行数据更新,用来标记当前是第几个状态
	if (States[i].monkey == 0)//猴子站在了位置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
		{ 
   
			monkeygoto(States[i].box, 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);
			climbonto(i);
			reach(i + 1);
			nextStep(j);
		}
		else
		{ 
   
			monkeygoto(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);
}

二、传教士(牧师)与野人问题

1、问题描述

有n个牧师和n个野人准备渡河,但只有一条能容纳c个人的小船,为了防止野人侵犯牧师,要求无论在何处,牧师的人数不得少于野人的人数(除非牧师人数为0),且假定野人与牧师都会划船,试设计一个算法,确定他们能否渡过河去,若能,则给出小船来回次数最少的最佳方案。

2、实验步骤

输入:牧师人数(即野人人数):n;小船一次最多载人量:c。
输出:若问题无解,则显示Failed,否则,显示Successed输出所有可行方案,并标注哪一组是最佳方案。用三元组(X1, X2, X3)表示渡河过程中的状态。并用箭头连接相邻状态以表示迁移过程:初始状态->中间状态->目标状态。

例:当输入n=2,c=2时,输出:221->200->211->010->021->000;
其中:X1表示起始岸上的牧师人数;X2表示起始岸上的野人人数;X3表示小船现在位置(1表示起始岸,0表示目的岸)。

3、实验要求

写出算法的设计思想和源程序,并有用户界面实现人机交互(控制台或者窗口都可以),进行输入和输出结果,如:
Please input n: 2 Please input c: 2
Optimal Procedure: 221->200->211->010->021->000
Successed or Failed?: Successed

4、解题思路

针对“传教士与野人”实验,输入不同的传教士与野人数目,允许过河的最大人数,可以得到不同的结果。在输出所有可行路径之后,输出最优路径,即所花次数最少的结果。
这题使用DFS算法,运用递归来写DFS算法,搜索扫描可能的路径,若可行则打印出来,同时比较当前路径是否比已存储的最短路径短,若是,则当前路径存储为最短路径,若否则跳过。

5、实验代码

// 传教士与野人.cpp 
#include <iostream>
using namespace std;
#define maxNum 150
struct op
{ 
   
	int M;	//牧师过河人数
	int C;	//野人过河人数
};
struct State
{ 
   
	int minister;	//起始岸上的牧师人数
	int savage;		//起始岸上的野人人数
	int side;		//side=0,船在初始岸,side=1,船在对岸
};

int n;		//牧师和野人数目
int c;		//小船最多能载的人数
int op_num;	//有多少种过河方式
int min_road=999;//最短路径
struct op opNum[maxNum];
struct State States[maxNum];
struct State StatesMin[maxNum];

//安全状态
int isSafe(int i)
{ 
   
	if (States[i].minister == 0 || States[i].minister == n || States[i].minister == States[i].savage)
		return 1;
	return 0;
}
//最终目标
int isGoal(int i)
{ 
   
	if (States[i].minister == 0 && States[i].savage == 0)
		return 1;
	return 0;
}
//判断是否跟之前的状态重复
int isRepeat(int i)
{ 
   
	for (int j = 0; j < i; j++)
	{ 
   
		if (States[i].minister == States[j].minister&&States[i].savage == States[j].savage&&States[i].side==States[j].side)
			return 1;
	}
	return 0;
}
//可选择的过河方式
void OpNum()
{ 
   
	for(int i=0;i<=c;i++)
		for (int j = 0; j <= i&&j<=c-i; j++)
		{ 
   
			opNum[op_num].M = i;
			opNum[op_num++].C = j;
		}
}
//存储最短的过河方式
void MinWay(int i)
{ 
   
	for (int j = 0; j <= i; j++)
	{ 
   
		StatesMin[j].minister = States[j].minister;
		StatesMin[j].savage = States[j].savage;
		StatesMin[j].side = States[j].side;
	}
}
//打印
void Print(State *state,int i)
{ 
   
	for (int j = 0; j < i; j++)
	{ 
   
		cout << state[j].minister << state[j].savage << state[j].side<<"->";
		if (j + 1 % 10 == 0)
			cout << endl;
	}
	cout << state[i].minister << state[i].savage << state[i].side <<endl<<endl;
}
//使用dfs遍历寻找解
void nextStep(int i)
{ 
   
	// 递归出口
	if (isGoal(i))
	{ 
   
		if (i < min_road)
		{ 
   
			min_road = i;
			MinWay(i);
		}
		cout << "Successed:" << endl;
		Print(States,i);
		return;
	}
	// 是否安全
	if (!isSafe(i))
		return;
	// 是否重复
	if (isRepeat(i))
		return;

	int j = i + 1;
	// 起始岸
	if (States[i].side == 0)
	{ 
   
		for (int k = 0; k < op_num; k++)
		{ 
   
			if (opNum[k].M > States[i].minister || opNum[k].C > States[i].savage)
				continue;
			States[j].minister = States[i].minister-opNum[k].M;
			States[j].savage = States[i].savage - opNum[k].C;
			States[j].side = 1;
			nextStep(j);
		}
	}
	else//对岸
	{ 
   
		for (int k = 0; k < op_num; k++)
		{ 
   
			if (opNum[k].M > (n-States[i].minister) || opNum[k].C > (n-States[i].savage))
				continue;
			States[j].minister = States[i].minister+opNum[k].M;
			States[j].savage = States[i].savage+opNum[k].C;
			States[j].side = 0;
			nextStep(j);
		}
	}
}

int main()
{ 
   
	cout << "Please input n: ";
	cin >> n;
	cout << "Please input c: ";
	cin >> c;
	States[0].minister = n;
	States[0].savage = n;
	States[0].side = 0;
	OpNum();
	nextStep(0);
	if (min_road < 999)
	{ 
   
		cout << "Optimal Procedure:" << endl;
		Print(StatesMin, min_road);
	}
	else
	{ 
   
		cout << "Fail." << endl;
	}
    return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/189334.html原文链接:https://javaforall.net

(0)
上一篇 2026年4月13日 下午11:13
下一篇 2026年4月13日 下午11:19


相关推荐

  • POJ 1679:The Unique MST(次小生成树&amp;&amp;Kruskal)[通俗易懂]

    POJ 1679:The Unique MST(次小生成树&amp;&amp;Kruskal)

    2022年1月27日
    78
  • mysql使用笔记

    mysql使用笔记

    2021年6月15日
    105
  • Linux visudo 命令

    Linux visudo 命令在类 Unix 操作系统上 visudo 命令编辑 sudo 命令使用的 sudoers 文件 要更改允许哪些用户和组运行 sudo 请运行 visudo 如果运行 sudo 的用户不符合 sudoers 中的身份验证配置 他们将被拒绝以升级的权限运行命令 您不应通过在文本编辑器中打开来直接编辑 sudoers 相反 使用 visudo 对其进行编辑 这将在将更改保存到磁盘之前验证其有效性 描述 visudo 编辑 sudoers 文件 该文件定义了具有管理员权限的用户和组 Visudo 以安全的方式编辑 sudoers

    2026年3月18日
    2
  • 【案例】10个视觉系优秀网页设计让你打破灵感的僵局

    【案例】10个视觉系优秀网页设计让你打破灵感的僵局nbsp 设计是一种归于内心世界的创造又是趋于大众喜爱的展现 尤其是优秀网页设计这一块更是如此 往往在这方面的设计上要考虑大多数人的爱好 与用户的交互以及人机对话的逻辑等等 而作为资源整合的操盘手 设计师就会将这些维度的东西进行整合 形成让大众怦然心动又粘性十足的网页作品 网页作为产品对外宣传的窗口 从视觉上首先就抓住用户眼睛 从设计美学上来讲色彩的碰撞 设计的素雅 结构的独特等等都是每设计师在考量

    2026年3月16日
    3
  • Stable Diffusion【插画转绘】:建筑风景照片转绘插画图片的制作教程

    Stable Diffusion【插画转绘】:建筑风景照片转绘插画图片的制作教程

    2026年3月15日
    1
  • C++实现二叉树层序遍历

    C++实现二叉树层序遍历层序遍历图示实现二叉树的层次遍历,要利用到队列。基本思想:1.先将根节点放到队列中2.根节点弹出队列,然后将根节点的左、右儿子入队3.弹出左儿子,放入左儿子的左右儿子4.弹出右儿子,放入右儿子的左右儿子5.重复3、4步图示过程:所用的二叉树如下队列的操作:将根节点弹出,放入左右儿子:将B节点弹出,放入左右儿子(只有右儿子):把D节点弹出,放入左右儿子:C、E、F都没有儿子节点,所以直接弹出队列即可: C++代码实现1.利用前序遍历思想输入二叉树。(前序

    2022年5月21日
    30

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号