野人与传教士问题 .(转载)

1.题目简述:有N个传教士和N个野人要过河,现在有一条船只能承载N个人(包括野人),在任何时刻,如果有野人和传教士在一起,必须要求传教士的人数多于或等于野人的人数。
2.解答描述:这题我通过人工只能基于生产式系统解答,其实就是算法中说的深度优先搜索算法。在自己归纳策略集的时候发现当N=1时一次就过去了,当N=2时只有两条规则,当N=3时有5条规则,当N=4时有9条规则,当N=5时有14条规则,所以取N=3时比较便于表达又有代表性(当然河对岸的规则相同)。
3.具体代码:
代码如下,所有思想基本标注:

 

  1. #include "stdafx.h"   
  2. #include<process.h>    
  3. #include<stdio.h>   
  4. #include <stdlib.h>   
  5. #define NULL 0   
  6. #define TRUE 1   
  7. #define FALSE 0   
  8. #define OK 1   
  9. #define ERROR 0   
  10.   
  11. typedef struct  
  12. {  
  13.     int m; //传教士人数   
  14.     int c; //野人人数   
  15.     int b; //船的位置变量   
  16. }QElemType; /* 定义队列的数据元素类型QElemType为结构体类型 */  
  17. typedef struct _Rule  
  18. {  
  19.     int m;//传教士人数   
  20.     int c;//野人人数   
  21. }Rule;  
  22.   
  23. Rule rule[5] = {{1,1}, {1,0}, {0,1}, {2,0}, {0,2}};  // 规则集e   
  24.   
  25. typedef struct QNode  
  26. {  
  27.     QElemType data;  
  28.     struct QNode *next;  
  29. }QNode,*QueuePtr;//节点结构体   
  30.   
  31. typedef struct  
  32. {  
  33.     QueuePtr front,rear; //队头、队尾指针    
  34. }LinkQueue;  
  35.   
  36. /* 构造一个空队列Q */  
  37. void InitQueue(LinkQueue *Q)  
  38. {   
  39.     (*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));  
  40.     if(!(*Q).front)  
  41.         exit(0);  
  42.     (*Q).front->next=NULL;  
  43. }  
  44.   
  45. /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */  
  46. int DeQueue(LinkQueue *Q,QElemType *e)  
  47. {   
  48.     QueuePtr p;  
  49.     if((*Q).front==(*Q).rear)  
  50.         return ERROR;  
  51.     p=(*Q).front->next;  
  52.     *e=p->data;  
  53.     (*Q).front->next=p->next;  
  54.     if((*Q).rear==p)  
  55.         (*Q).rear=(*Q).front;  
  56.     free(p);  
  57.     return OK;  
  58. }  
  59.   
  60.  /* 插入元素e为Q的新的队尾元素 */  
  61. void EnQueue(LinkQueue *Q,QElemType e)  
  62. {  
  63.     QueuePtr p=(QueuePtr)malloc(sizeof(QNode));  
  64.   
  65.     if(!p)   
  66.         exit(0);  
  67.     p->data=e;  
  68.     p->next=NULL;  
  69.     (*Q).rear->next=p;  
  70.     (*Q).rear=p;  
  71. }  
  72.   
  73. /* 若Q队列,有给定节点返回true,否则返回false */  
  74. int cmp(LinkQueue *Q,QElemType e){   
  75.     QueuePtr p=(*Q).front->next;  
  76.     while(p!=NULL){  
  77.   
  78.         if(p->data.m==e.m&&p->data.c==e.c&&p->data.b==e.b)  
  79.             return TRUE;  
  80.   
  81.   
  82.         else p=p->next;  
  83.     }  
  84.     return FALSE;  
  85. }  
  86.   
  87. /* 若Q为空队列,则返回TRUE,否则返回FALSE */  
  88. int QueueEmpty(LinkQueue Q)  
  89. {   
  90.     if(Q.front->next==NULL)  
  91.         return TRUE;  
  92.     else  
  93.         return FALSE;  
  94. }  
  95.   
  96. void main(){  
  97.     LinkQueue open,closed;  //定义首尾指针   
  98.     QueuePtr p;  //定义节点指针   
  99.     int i;  
  100.     InitQueue(&open);  //初始化open队列   
  101.     InitQueue(&closed);   //初始化closed队列   
  102.     QElemType s={3,3,1},e,e1;   //初始化初始节点s,3个传教士,3个野人,船在左岸   
  103.     EnQueue(&open,s);    //将s入列   
  104.     while(!QueueEmpty(open)){  
  105.         DeQueue(&open,&e);  
  106.         EnQueue(&closed,e);  
  107.         if(e.m==0&&e.c==0&&e.b==0)//判断条件控制策略是否结束   
  108.         {printf("成功!");  
  109.         continue;}  
  110.         for(i=0;i<5;i++)  //因为控制策略只有5步所以这里循环5次   
  111.         {e1.m=e.m,e1.c=e.c,e1.b=e.b;  
  112.         if(e1.b==1)//船在左岸,对数据库做减法   
  113.         {  
  114.             e1.m=e1.m-rule[i].m;  
  115.             e1.c=e1.c-rule[i].c;   
  116.             e1.b=0;  
  117.             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)  
  118.             {if(!cmp(&closed,e1))  
  119.             if(!cmp(&open,e1))  
  120.                 EnQueue(&open,e1);}//需要解决元素问题   
  121.         }//if   
  122.         else //船在右岸,对数据库做加法   
  123.         {e1.m=e1.m+rule[i].m;  
  124.         e1.c=e1.c+rule[i].c;  
  125.         e1.b=1;  
  126.         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)  
  127.         {if(!cmp(&closed,e1))  
  128.         if(!cmp(&open,e1))  
  129.             EnQueue(&open,e1);}//需要解决元素重复问题   
  130.         }//else   
  131.         }//for   
  132.     }//while   
  133.     p=closed.front;//指向结果集   
  134.     p=p->next;  
  135.     printf("\n");  
  136.     while(p!=NULL){  
  137.         printf("%d,%d,%d\n",p->data.m,p->data.c,p->data.b);//打印解决结果   
  138.         p=p->next;  
  139.     }  
  140.     getchar();//停顿函数   
  141. }   
#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();//停顿函数
} 


实验结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值