野人与传教士问题

1.题目简述:有N个传教士和N个野人要过河,现在有一条船只能承载N个人(包括野人),在任何时刻,如果有野人和传教士在一起,必须要求传教士的人数多于或等于野人的人数。

2.解答描述:这题我通过人工只能基于生产式系统解答,其实就是算法中说的深度优先搜索算法。在自己归纳策略集的时候发现当N=1时一次就过去了,当N=2时只有两条规则,当N=3时有5条规则,当N=4时有9条规则,当N=5时有14条规则,所以取N=3时比较便于表达又有代表性(当然河对岸的规则相同)。

3.具体代码:

代码如下,所有思想基本标注:

#include "stdafx.h"
#include<process.h>
#include<stdio.h>
#include <stdlib.h>
#define NULL 0
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0

typedef struct
{
	int m; //传教士人数
	int c; //野人人数
	int b; //船的位置变量
}QElemType; /* 定义队列的数据元素类型QElemType为结构体类型 */
typedef struct _Rule
{
	int m;//传教士人数
	int c;//野人人数
}Rule;

Rule rule[5] = {{1,1}, {1,0}, {0,1}, {2,0}, {0,2}};  // 规则集e

typedef struct QNode
{
	QElemType data;
	struct QNode *next;
}QNode,*QueuePtr;//节点结构体

typedef struct
{
	QueuePtr front,rear; //队头、队尾指针
}LinkQueue;

/* 构造一个空队列Q */
void InitQueue(LinkQueue *Q)
{
	(*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
	if(!(*Q).front)
		exit(0);
	(*Q).front->next=NULL;
}

/* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
int DeQueue(LinkQueue *Q,QElemType *e)
{
	QueuePtr p;
	if((*Q).front==(*Q).rear)
		return ERROR;
	p=(*Q).front->next;
	*e=p->data;
	(*Q).front->next=p->next;
	if((*Q).rear==p)
		(*Q).rear=(*Q).front;
	free(p);
	return OK;
}

 /* 插入元素e为Q的新的队尾元素 */
void EnQueue(LinkQueue *Q,QElemType e)
{
	QueuePtr p=(QueuePtr)malloc(sizeof(QNode));

	if(!p)
		exit(0);
	p->data=e;
	p->next=NULL;
	(*Q).rear->next=p;
	(*Q).rear=p;
}

/* 若Q队列,有给定节点返回true,否则返回false */
int cmp(LinkQueue *Q,QElemType e){
	QueuePtr p=(*Q).front->next;
	while(p!=NULL){

		if(p->data.m==e.m&&p->data.c==e.c&&p->data.b==e.b)
			return TRUE;

		else p=p->next;
	}
	return FALSE;
}

/* 若Q为空队列,则返回TRUE,否则返回FALSE */
int QueueEmpty(LinkQueue Q)
{
	if(Q.front->next==NULL)
		return TRUE;
	else
		return FALSE;
}

void main(){
	LinkQueue open,closed;  //定义首尾指针
	QueuePtr p;  //定义节点指针
	int i;
	InitQueue(&open);  //初始化open队列
	InitQueue(&closed);   //初始化closed队列
	QElemType s={3,3,1},e,e1;   //初始化初始节点s,3个传教士,3个野人,船在左岸
	EnQueue(&open,s);    //将s入列
	while(!QueueEmpty(open)){
		DeQueue(&open,&e);
		EnQueue(&closed,e);
		if(e.m==0&&e.c==0&&e.b==0)//判断条件控制策略是否结束
		{printf("成功!");
		continue;}
		for(i=0;i<5;i++)  //因为控制策略只有5步所以这里循环5次
		{e1.m=e.m,e1.c=e.c,e1.b=e.b;
		if(e1.b==1)//船在左岸,对数据库做减法
		{
			e1.m=e1.m-rule[i].m;
			e1.c=e1.c-rule[i].c;
			e1.b=0;
			if((e1.m>=e1.c||e1.m==0)&&((3-e1.m)>=(3-e1.c)||(3-e1.m)==0)&&e1.m<=3&&e1.c<=3&&e1.m>=0&&e1.c>=0)
			{if(!cmp(&closed,e1))
			if(!cmp(&open,e1))
				EnQueue(&open,e1);}//需要解决元素问题
		}//if
		else //船在右岸,对数据库做加法
		{e1.m=e1.m+rule[i].m;
		e1.c=e1.c+rule[i].c;
		e1.b=1;
		if((e1.m>=e1.c||e1.m==0)&&((3-e1.m)>=(3-e1.c)||(3-e1.m)==0)&&e1.m<=3&&e1.c<=3&&e1.m>=0&&e1.c>=0)
		{if(!cmp(&closed,e1))
		if(!cmp(&open,e1))
			EnQueue(&open,e1);}//需要解决元素重复问题
		}//else
		}//for
	}//while
	p=closed.front;//指向结果集
	p=p->next;
	printf("\n");
	while(p!=NULL){
		printf("%d,%d,%d\n",p->data.m,p->data.c,p->data.b);//打印解决结果
		p=p->next;
	}
	getchar();//停顿函数
}

实验结果:

野人与传教士问题

时间: 2024-11-04 23:40:52

野人与传教士问题的相关文章

传教士-野人问题

题目: 有N个传教士和N个野人要过河,现在有一条船只能承载M个人,在任何时刻,如果有野人和传教士在一起,必须要求传教士的人数多于或等于野人的人数(包括船上和两个岸边). 设M为传教士的人数,C为野人的人数,当N=3, M=2时, 用状态空间法求解此问题的过程如下: (1)设置状态变量并确定值域 S.C = N,B = { 0 , 1} (1表示在岸边),要求在船上S>=C且S+C <= M 初始状态       目标状态   L R S 3 0 C 3 0 B 1 0   L R S 0 3

【转】传教士和野人问题(Missionaries and Cannibals)

传教士和野人问题(Missionaries   and   Cannibals)    这是一个经常在有关讨论人工智能的书籍中见到的问题,   其描述是这样的:    有N个传教士和N个野人来到河边渡河,   河岸有一条船,   每次至多可供k人乘渡.问传教士为了安全起见,   应如何规划摆渡方案,   使得任何时刻,   河两岸以及船上的野人数目总是不超过传教士的数目(否则不安全,   传教士有可能被野人吃掉).即求解传教士和野人从左岸全部摆渡到右岸的过程中,   任何时刻满足M(传教士数)≥

过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(第2届第2题)

题目要求 问题描述:三只牛三只虎过河,船最多只能容纳两只动物,且船在往返途中不能为空.在任一岸边,若牛的数量少于虎的数量,则牛就会被老虎吃掉.为了使动物全部过河且使无损失,请制定合理的渡河方案. 解决方案 这也是一个经典的渡河问题了,由此衍化出的版本有商人仆人(随从)过河,农夫妖怪过河,传教士野人过河...除了角色有变化,内容本质上是一样的. 假设原来的动物和船都在A岸,现在想渡河到对面的B岸.考虑牛虎数量和船的位置,可以将本题中的所有可能出现的情形描述为静态属性和动态属性.静态属性就是船停靠在

传教士与野人过河问题(A*搜索 C++)

传教士与野人过河问题: 任意时刻,左岸.右岸.船上如果传教士人数少于野人人数,传教士就会被野人吃掉.当然野人会划船.传教士人数为0也是可以的. 启发函数 f=g+h.  g当前结点所在解空间树的深度.h=m+c-2*b. m,c分别是当前状态下左岸传教士和野人的数目.b=1表示当前船在左岸停靠.b=0表示当前状态船在右岸. #include<vector> #include<algorithm> #include<stdio.h> #include<stdlib.

野人传教士过河问题

摘要:北京时间3月12日下午,谷歌人工智能AlphaGo与韩国棋手李世石今日进行了第三场较量,最终AlphaGo战胜李世石,连续取得三场胜利. 随着又一次的人工智能与人类智能的世纪大战,我们不禁要思索,人工智能,是在呼唤上帝还是在召唤恶魔?此时正是时候研究一下人工智能相关理论,而本文主要论述计算机科学与技术专业大三下专业课<人工智能>第一个实验算法. 关键字:人工智能,搜索问题,树的深度优先搜索 The Missionaries and Cannibals Problem Abstract:

修道士和野人问题

休闲时刻看看神经网络方面的书,发现了修道士和野人的问题,不禁勾引起我写算法的欲望,曾经的三只大老虎三只小老虎过河问题.人狼羊白菜过河问题.汉诺塔.哈夫曼等等各种算法瞬间在脑海中约隐约现,修道士和野人问题我以前好像没有解开,中午吃饭的时候在脑海中重新构造思路,下午耗了点时间把它干掉.(算法不在代码里,而在思想中:所以尽量不要看我的代码,而要仔细分析我写的思路) 题目: 设有3个修道士和3个野人来到河边, 打算用一条船从河的左岸渡到河的右岸.但该船每次只能装载两个人, 在任何岸边野人的数目都不得超过

【BZOJ】1407 NOI 2002 荒岛野人Savage

拓展欧几里得入门题 两个野人若要走到同一个洞穴,设他们走了x步,则p[i]*x+c[i]≡p[j]*x+c[j](mod ans),ans即答案: 移项得到(p[i]-p[j])*X+ansY=c[j]-c[i]; 即aX+bY+=C的形式,枚举ans,n^2的枚举每一个野人,用ex_gcd求得最小解,看X是否在他们的生命时间内. 1 /************************************************************** 2 Problem: 1407 3

[NOI2002] 荒岛野人 扩展欧几里得算法

[问题描述] 克里特岛以野人群居而著称.岛上有排列成环行的M个山洞.这些山洞顺时针编号为1,2,-,M.岛上住着N个野人,一开始依次住在山洞 C1,C2,-,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来.每个野人i有一个寿命值Li,即生存的年数.下面四幅图描述了一个有6个 山洞,住有三个野人的岛上前四年的情况.三个野人初始的洞穴编号依次为1,2,3:每年要走过的洞穴数依次为3,7,2:寿命值依次为4,3,1.     奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个

CodeVS1747_NOI2002_荒岛野人_Savage_C++

题目:http://codevs.cn/problem/1747/ 对于一个环,我们经常用取余来表示它走过若干圈后的位置 那么第 i 个野人第 x 年时所在的位置可表示为:(c[i]+p[i]*x)%m (若结果为 0 则变为 m) 若两个野人不产生冲突,则在它们俩最小的寿命之内,每一年的位置都会不同 可列出不等式,对于第 i 和第 j 号野人,(c[i]+p[i]*x)%m!=(c[j]+p[j]*x)%m 但是不等式十分不好解,则把它转化为等式,并做变换 (c[i]+p[i]*x)%m=(c