农夫过河问题(C++编写)

合集下载

农夫过河C语言课程设计

农夫过河C语言课程设计

农夫过河C语言课程设计一、课程目标知识目标:1. 理解C语言中基本的数据类型和语法结构;2. 学会使用C语言进行逻辑判断和循环控制;3. 掌握C语言中的函数定义和调用方法;4. 了解“农夫过河”问题的背景和解决方案。

技能目标:1. 能够运用C语言编写出解决“农夫过河”问题的程序;2. 培养逻辑思维和问题分析能力,将实际问题转化为程序代码;3. 提高编程实践能力,学会调试和修改代码,解决程序中的错误。

情感态度价值观目标:1. 激发学生对编程的兴趣,培养计算机科学素养;2. 培养学生面对问题积极思考、勇于探索的精神;3. 强调团队合作,学会与他人共同解决问题,培养沟通与协作能力。

分析课程性质、学生特点和教学要求:本课程为C语言编程课程,旨在让学生掌握C语言的基本知识,并通过解决实际问题,提高编程能力。

学生为初中生,具有一定的逻辑思维能力和数学基础。

教学要求注重实践,将理论教学与实际操作相结合,引导学生主动参与,培养其独立思考和解决问题的能力。

课程目标分解:1. 知识目标:通过讲解和实例演示,让学生掌握C语言的基本知识;2. 技能目标:通过编写“农夫过河”程序,提高学生的编程实践能力;3. 情感态度价值观目标:通过课程教学,激发学生对编程的兴趣,培养其积极思考、勇于探索的精神,以及团队合作能力。

二、教学内容1. C语言基础知识回顾:- 数据类型、变量、常量- 运算符、表达式、语句- 选择结构(if-else)- 循环结构(for、while、do-while)2. 函数定义与调用:- 函数的概念和作用- 函数的定义、声明和调用- 递归函数的原理和应用3. “农夫过河”问题分析:- 问题的描述和规则- 状态表示和状态空间- 搜索策略(深度优先、广度优先)4. 编程实践:- 设计“农夫过河”问题的算法- 编写C语言程序实现算法- 调试和优化程序5. 教学内容安排与进度:- 第一课时:C语言基础知识回顾,引入“农夫过河”问题- 第二课时:函数定义与调用,分析问题并设计算法- 第三课时:编写程序,实现“农夫过河”算法- 第四课时:调试优化程序,总结经验,展示成果教学内容关联教材章节:- 《C语言程序设计》第一章:C语言概述- 《C语言程序设计》第二章:数据类型与运算符- 《C语言程序设计》第三章:控制结构- 《C语言程序设计》第四章:函数- 《C语言程序设计》第十章:算法与程序设计实例教学内容注重科学性和系统性,结合教材章节,使学生能够在掌握C语言基础知识的基础上,学会解决实际问题,提高编程能力。

农夫过河问题

农夫过河问题

一、题目:农夫过河问题二、目的与要求1、目的:通过布置具有一定难度的实际程序设计项目,使学生进一步理解和掌握课堂上所学各种基本抽象数据类型的逻辑结构、存储结构和操作实现算法,以及它们在程序中的使用方法;使学生掌握分析问题,求解问题的方法并提高学生设计编程实现的能力。

2、要求:基本要求:1.要求利用C\C++语言来完成系统的设计;2.突出C语言的函数特征(以多个函数实现每一个子功能)或者C++语言面向对象的编程思想;3.画出功能模块图;4.进行简单界面设计,能够实现友好的交互;5.具有清晰的程序流程图和数据结构的详细定义;6.熟练掌握C语言或者C++语言的各种操作。

创新要求:在基本要求达到后,可进行创新设计,如系统用户功能控制,改进算法的实现,实现友好的人机交互等等三、问题描述和求解方法:1 、问题描述要求设计实现农夫过河问题(农夫带着一只狼,一只养,一棵白菜,一次只能带一个东西)如何安全过河。

2 、问题的解决方案:可以用栈与队列、深度优先搜索算法及广度优先搜索算法相应的原理去解决问题。

1)实现四个过河对象(农夫、白菜、羊和狼)的状态,可以用一个四位二进制数来表示,0表示未过河,1表示已经过河了。

2)过河的对象必须与农夫在河的同一侧,可以设计函数来判断。

3)防止状态往复,即农夫将一个东西带过去又带回来的情况发生,需将所有可能的状态进行标定。

4)可用深度优先搜索算法及广度优先搜索算法去解题。

四、解题过程1.分析程序的功能要求,划分程序功能模块。

2.画出系统流程图。

3.代码的编写。

定义数据结构和各个功能子函数。

4.程序的功能调试。

5.完成系统总结报告以及使用说明书五、进度安排此次课程设计时间为一周,分以下几个阶段完成:1.选题与搜集资料:每人选择一题,进行课程设计课题的资料搜集。

2.分析与概要设计:根据搜集的资料,进行程序功能与数据结构分析,并选择合适的数据结构、并在此基础上进行实现程序功能的算法设计。

数据结构实验-农夫过河问题

数据结构实验-农夫过河问题

农夫过河问题一、实验目的掌握广度优先搜索策略,并用队列求解农夫过河问题二、实验内容问题描述:一农夫带着一只狼,一只羊和一颗白菜,身处河的南岸,他要把这些东西全部运到北岸,遗憾的是他只有一只小船,小船只能容下他和一件物品。

这里只能是农夫来撑船,同时因为狼吃羊、羊吃白菜、所以农夫不能留下羊和狼或羊和白菜在河的一边,而自己离开;好在狼属肉食动物,不吃白菜。

农夫怎么才能把所有的东西安全运过河呢?实验要求如下:(1)设计物品位置的表示方法和安全判断算法;(2)设计队列的存储结构并实现队列的基本操作(建立空队列、判空、入队、出队、取对头元素),也可以使用STL中的队列进行代码的编写;(3)采用广度优先策略设计可行的过河算法;(4)输出要求:按照顺序输出一种可行的过河方案;提示:可以使用STL中的队列进行代码编写。

程序运行结果:二进制表示:1111011011100010101100011001,0000三、农夫过河算法流程⏹Step1:初始状态0000入队⏹Step2:当队列不空且没有到达结束状态1111时,循环以下操作:⏹队头状态出队⏹按照农夫一个人走、农夫分别带上三个物品走,循环以下操作:⏹农夫和物品如果在同一岸,则计算新的状态⏹如果新状态是安全的并且是没有处理过的,则更新path[ ],并将新状态入队⏹当状态为1111时,逆向输出path[ ]数组附录一:STL中队列的使用注:队列,可直接用标准模板库(STL)中的队列。

需要#include<queue>STL中的queue,里面的一些成员函数如下(具体可以查找msdn,搜索queue class):front:Returns a reference to the first element at the front of the queue.pop:Removes an element from the front of the queuepush:Adds an element to the back of the queueempty:Tests if the queue is empty三、实验代码FarmerRiver.H#ifndef FARMERRIVER_H#define FARMERRIVER_Hint FarmerOnRight(int status); //农夫,在北岸返回1,否则返回0int WorfOnRight(int status); //狼int CabbageOnRight(int status); //白菜int GoatOnRight(int status); //羊int IsSafe(int status); //判断状态是否安全,安全返回1,否则返回0void FarmerRiver();#endifSeqQueue.h#ifndef SEQQUEUE_H#define SEQQUEUE_Htypedef int DataType;struct Queue{int Max;int f;int r;DataType *elem;};typedef struct Queue *SeqQueue;SeqQueue SetNullQueue_seq(int m);int IsNullQueue_seq(SeqQueue squeue);void EnQueue_seq(SeqQueue squeue, DataType x);void DeQueue_seq(SeqQueue);DataType FrontQueue_seq(SeqQueue);#endifFarmerRiver.c#include <stdio.h>#include <stdlib.h>#include "SeqQueue.h"#include "FarmerRiver.h"int FarmerOnRight(int status) //判断当前状态下农夫是否在北岸{return (0!=(status & 0x08));}int WorfOnRight(int status){return (0!=(status & 0x04));}int CabbageOnRight(int status){return (0!=(status & 0x02));}int GoatOnRight(int status){return (0!=(status & 0x01));}int IsSafe(int status) //判断当前状态是否安全{if ((GoatOnRight(status)==CabbageOnRight(status)) && (GoatOnRight(status)!=FarmerOnRight(status)))return (0); //羊吃白菜if ((GoatOnRight(status)==WorfOnRight(status)) && (GoatOnRight(status)!=FarmerOnRight(status))) return 0; //狼吃羊return 1; //其他状态是安全的}void FarmerRiver(){int i, movers, nowstatus, newstatus;int status[16]; //用于记录已考虑的状态路径SeqQueue moveTo;moveTo = SetNullQueue_seq(20); //创建空列队EnQueue_seq(moveTo, 0x00); //初始状态时所有物品在北岸,初始状态入队for (i=0; i<16; i++) //数组status初始化为-1{status[i] = -1;}status[0] = 0;//队列非空且没有到达结束状态while (!IsNullQueue_seq(moveTo) && (status[15]==-1)){nowstatus = FrontQueue_seq(moveTo); //取队头DeQueue_seq(moveTo);for (movers=1; movers<=8; movers<<=1)//考虑各种物品在同一侧if ((0!=(nowstatus & 0x08)) == (0!=(nowstatus & movers)))//农夫与移动的物品在同一侧{newstatus = nowstatus ^ (0x08 | movers); //计算新状态//如果新状态是安全的且之前没有出现过if (IsSafe(newstatus)&&(status[newstatus] == -1)){status[newstatus] = nowstatus; //记录新状态EnQueue_seq(moveTo, newstatus); //新状态入队}}}//输出经过的状态路径if (status[15]!=-1){printf("The reverse path is: \n");for (nowstatus=15; nowstatus>=0; nowstatus=status[nowstatus]){printf("The nowstatus is: %d\n", nowstatus);if (nowstatus == 0)return;}}elseprintf("No solution.\n");}Sequeue.c#include <stdio.h>#include <stdlib.h>#include "SeqQueue.h"SeqQueue SetNullQueue_seq(int m){SeqQueue squeue;squeue = (SeqQueue)malloc(sizeof(struct Queue));if (squeue==NULL){printf("Alloc failure\n");return NULL;}squeue->elem = (int *)malloc(sizeof(DataType) * m);if (squeue->elem!=NULL){squeue->Max = m;squeue->f = 0;squeue->r = 0;return squeue;}else free(squeue);}int IsNullQueue_seq(SeqQueue squeue){return (squeue->f==squeue->r);}void EnQueue_seq(SeqQueue squeue, DataType x) //入队{if ((squeue->r+1) % squeue->Max==squeue->f) //是否满printf("It is FULL Queue!");else{squeue->elem[squeue->r] = x;squeue->r = (squeue->r+1) % (squeue->Max);}}void DeQueue_seq(SeqQueue squeue) //出队{if (IsNullQueue_seq(squeue))printf("It is empty queue!\n");elsesqueue->f = (squeue->f+1) % (squeue->Max); }DataType FrontQueue_seq(SeqQueue squeue) //求队列元素{if (squeue->f==squeue->r)printf("It is empty queue!\n");elsereturn (squeue->elem[squeue->f]);}main.c#include <stdio.h>#include <stdlib.h>#include "FarmerRiver.h"int main(void){FarmerRiver();return 0;}实验结果:四、实验总结。

农夫过河问题回溯法python实现

农夫过河问题回溯法python实现

农夫过河问题是经典的逻辑谜题,在这个问题中,农夫需要把一只狼、一只羊和一棵白菜一起带过河。

然而,农夫只有一条小船,而且小船只能容纳农夫和另外一样东西。

而且,如果农夫不在场的话,狼会吃羊,羊会吃白菜。

所以农夫需要想办法把它们一一带过河,而且又不能让狼吃羊或者羊吃白菜。

这个问题看似简单,实际上需要一定的逻辑推理和计划安排才能成功通过。

回溯法是一种常用于解决这类问题的算法。

在计算机科学中,回溯法常常用于解决组合优化问题,它通过不断地尝试所有可能的步骤,直到找到解决方案为止。

在农夫过河问题中,回溯法可以帮助我们列举所有的可能方案,然后找出最优的解决方案。

下面我们将使用Python语言来实现农夫过河问题的回溯法解决方案。

1. 定义问题的状态空间在农夫过河问题中,我们可以定义每一种状态为(农夫位置, 狼位置, 羊位置, 白菜位置)。

其中,农夫位置、狼位置、羊位置和白菜位置均可取值为"左岸"或"右岸"。

(左岸, 左岸, 左岸, 左岸)代表所有的物品都在左岸,而农夫则准备过河。

2. 定义可行动作根据问题的描述,我们可以定义农夫可以采取的可行动作。

具体来说,农夫可以选择带一样东西过河,也可以选择不带东西过河。

我们可以定义可行动作为("不带东西过河"), ("狼过河"), ("羊过河"), ("白菜过河")。

3. 实现回溯法接下来,我们可以使用递归的方式来实现回溯法。

具体来说,我们可以定义一个递归函数backtrack(state, path),其中state表示当前的状态,path表示从起始状态到当前状态的路径。

在递归函数中,我们首先判断是否已经找到了解决方案,如果是,则输出路径并返回;否则,我们尝试所有可行的动作,递归地调用backtrack函数,直到找到解决方案为止。

4. 完整代码实现下面是使用Python语言实现农夫过河问题的回溯法解决方案的完整代码:```pythondef is_valid(state):if state[1] == state[2] and state[0] != state[1]:return Falseif state[2] == state[3] and state[0] != state[2]:return Falsereturn Truedef backtrack(state, path):if state == ('右岸', '右岸', '右岸', '右岸'):print(path)returnactions = [(0, 0), (1, 0), (0, 1), (1, 1)]for i in range(4):new_state = tuple((state[j] if j < 3 else '左岸' if state[j] == '右岸' else '右岸') for j in range(4))if 0 in actions[i] and is_valid(new_state):backtrack(new_state, path + [(actions[i], new_state)])elif is_valid(new_state) and is_valid(tuple([new_state[j] if j != k else state[j] for j in range(4) for k in range(3, 4)])):backtrack(new_state, path + [(actions[i], new_state)])if __name__ == "__m本人n__":initial_state = ('左岸', '左岸', '左岸', '左岸')backtrack(initial_state, [])```在上面的代码中,我们首先定义了一个辅助函数is_valid,该函数用于判断当前状态是否合法。

农夫过河问题

农夫过河问题

农夫过河问题
一、先分析农夫过河的情景:1.他走到了小桥上,遇见了大象;2.他看见小桥很窄,不能通过大象,于是下来,又看见了小兔子;3.小兔子让他再回去把自己带来的萝卜给小猴子送去;4.他想了想,就决定去找乌龟帮忙。

二、农夫为什么要这样做?我们可以用图中所示的几种方法来解答:(1)如果你是农夫,你会怎么办呢?(2)我们在学习时也常常有这样的问题,面对某个复杂的问题,总是从多角度考虑它,然后得出最佳的解决方案。

比如我们要学好数学,需要同学之间互相讨论交流,取长补短,共同进步。

三、根据刚才提供的信息和已经确立的条件,你认为哪些条件更重要?请写出两点理由并说明原因。

四、结合生活实际谈谈应该怎样正确处理人与人之间的关系。

数据结构课程设计-农夫过河-实验报告.

数据结构课程设计-农夫过河-实验报告.

一、需求分析描述1、针对实现整个过程需要多步,不同步骤中各个事物所处位置不同的情况,可定义一个结构体来实现对四个对象狼、羊、白菜和农夫的表示。

对于起始岸和目的岸,可以用0或者1来表示,以实现在程序设计中的简便性。

2、题目要求给出四种事物的过河步骤,没有对先后顺序进行约束,这就需要给各个事物依次进行编号,然后依次试探,若试探成功,进行下一步试探。

这就需要使用循环或者递归算法,避免随机盲目运算且保证每种情况均试探到。

3、题目要求求出农夫带一只羊,一条狼和一颗白菜过河的办法,所以依次成功返回运算结果后,需要继续运算,直至求出结果,即给出农夫的过河方案。

4、输出界面要求具有每一步中农夫所带对象及每步之后各岸的物体,需要定义不同的数组来分别存储上述内容,并使界面所示方案清晰简洁。

二、系统架构设计1.设计中首先涉及的就是数据类型的定义,首先,定义一个结构体用来存放农夫、狼、羊、白菜的信息。

具体定义为:struct Condition{int farmer;int wolf;int sheep;int cabbage;};定义了一个结构体数组Condition conditions[100],定义状态数组用来记录他们过河的状态0:起始岸;1:目的岸;程序中定义的char action100数组用来存放各个物件以及人过河或返回的说明语句。

2.程序中定义的子函数有:2.1 将狼带到目的岸以及带回起始岸的函数takeWolfOver()和takeWolfBack ();takeWolfOver()函数中将conditions[i+1].wolf=1,白菜、羊的状态不变,同时要有action[i]=" take wolf over."将狼带到目的岸语句;takeWolfBack()函数中将conditions[i+1].wolf=0,白菜、羊的状态不变,同时要有action[i]=" take wolf back."将狼带回起始岸语句。

农夫过河问题的求解

void ListTraverse(LinkType p, status(*visit)(LinkType q));
//从p(P!=NULL)指示的结点开始,依次对每个结点调用函数visit
其中部分操作的伪码算法如下:
BOOL InitList(OrderdeList &L)
{
if(MakeNode(head,ˊˊ)){ //头结点的虚设元素为空格符ˊˊ
{
//分配由p指向的数据元素为e、后继为“空”的结点,并返回TRUE,
//若分配失败,则返回FALSE
p=(Link Type)malloc(sixeof(Node Type));
if(!p)return FALSE;
p->data=e;p->next=NULL; return TRUE;
}
void freeNode(LinkType &p)
//销毁有序链表L
bool Listempty(OrderedList L);
//若L不存在或为“空表”,则返回TRUE,否则返回FALSE
int ListLengty(OrderedList L);
//返回链表的长度
Linktype GetelemPos(OrderedList L, int pos);
构造有序集算法createset读入n个元素逐个用locateelem判定不在当前集合中及确定插入位置后才用insertafetr插入到有序集中所以时间复杂度是on求并集算法union利用集合的有序性将两个集合的个元素不重复地依次利用append插入到当前并集的末尾故可在omn时间内完成
实验报告
题目:编制一个演示农夫过河问题的求解的程序
per=L.head; p=pre->next;

农夫过河问题

{
df=d[i].f-d[j].f;
dw=abs(d[i].w-d[j].w);
ds=abs(d[i].s-d[j].s);
dc=abs(d[i].c-d[j].c);
if(df!=0&&(dw+ds+dc)<=1)
{
edge[num].col=i;
edge[num++].row=j;
}
}
return num;
int right_edge(DataType *vertex,RowCol *edge,int n) //选出满足题意的边
void DepthFSearch(AdjLGraph G,int v,int visited[],DataType vert[],int *a)
//图的深度优先遍历
3.3抽象数据类型的设计
{
if(!visited[w])
DepthFSearch(G,w,visited,d1,s);
w=GetNextVex(G,v,w);
}
}
4.3函数的调用关系图
5.测试结果
农夫过河问题
1.问题描述
一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。他要把这些东西全部运到北岸。他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。
typedef struct
{
AdjLHeight a[100];//邻接表数组
int numOfVerts;//结点个数
int numOfEdges;//边个数

数据结构—农夫过河问题

题目:一个农夫带着一匹狼、一只羊、一颗白菜要过河,只有一条船而且农夫每次最多只能带一个动物或物品过河,并且当农夫不在的时候狼会吃羊,羊会吃白菜,列出所有安全将所有动物和物品带过河的方案。

要求:广度优先搜索农夫过河解,并输出结果源代码:#include <stdio.h>#include <stdlib.h>typedef int DataType;struct SeqQueue{int MAXNUM;int f, r;DataType *q;};typedef struct SeqQueue *PSeqQueue; // 顺序队列类型的指针类型PSeqQueue createEmptyQueue_seq(int m)//创建一个空队列{PSeqQueue queue = (PSeqQueue)malloc(sizeof(struct SeqQueue)); if (queue != NULL){queue->q = (DataType*)malloc(sizeof(DataType) *m);if (queue->q){queue->MAXNUM = m;queue->f = 0;queue->r = 0;return (queue);}elsefree(queue);}printf("Out of space!!\n"); // 存储分配失败return NULL;}int isEmptyQueue_seq(PSeqQueue queue)//判断队列是否为空{return (queue->f == queue->r);}void enQueue_seq(PSeqQueue queue, DataType x)//入队{if ((queue->r + 1) % queue->MAXNUM == queue->f)printf("Full queue.\n");else{queue->q[queue->r] = x;queue->r = (queue->r + 1) % queue->MAXNUM;}}void deQueue_seq(PSeqQueue queue)// 删除队列头部元素{if (queue->f == queue->r)printf("Empty Queue.\n");elsequeue->f = (queue->f + 1) % queue->MAXNUM;}DataType frontQueue_seq(PSeqQueue queue)//取队头元素{if (queue->f == queue->r)printf("Empty Queue.\n");elsereturn (queue->q[queue->f]);}int farmer(int location)//判断农夫的位置 1000表示在北岸{return (0 != (location &0x08));}int wolf(int location)//判断狼的位置 0100表示在北岸{return (0 != (location &0x04));}int cabbage(int location)//判断白菜的位置 0010表示在北岸{return (0 != (location &0x02));}int goat(int location)//判断羊的位置 0001表示在北岸{return (0 != (location &0x01));}int safe(int location)//安全状态的判断{if ((goat(location) == cabbage(location)) && (goat(location) != farmer(location))) //羊与白菜不安全return 0;if ((goat(location) == wolf(location)) && (goat(location) != farmer(location)))//羊与狼不安全return 0;return 1; // 其他状态是安全的}void bin_print(int num)//将十进制数转换成二进制数输出{char tmp[4];int i;for (i = 0; i < 4; ++i){tmp[i] = num & 0x01;num >>= 1;}for (i = 3; i >= 0; --i)putchar((tmp[i] == 0)?'0':'1');return;}int main(){int i, movers, location, newlocation;int a=0;int r[16];int route[16]; //用于记录已考虑的状态路径PSeqQueue moveTo; //用于记录可以安全到达的中间状态moveTo = createEmptyQueue_seq(20); //创建空队列enQueue_seq(moveTo, 0x00); //初始状态进队列for (i = 0; i < 16; i++)route[i] = -1; //准备数组route初值route[0] = 0;while (!isEmptyQueue_seq(moveTo) && (route[15] == - 1)){location = frontQueue_seq(moveTo); //取队头状态为当前状态deQueue_seq(moveTo);for (movers = 1; movers <= 8; movers <<= 1)//考虑各种物品移动 if ((0 != (location & 0x08)) == (0 != (location & movers)))//判断农夫与移动的物品是否在同一侧{newlocation = location ^ (0x08 | movers);//计算新状态,代表把船上的(0x08|movers)从一个岸移到另一个岸;(0x08|movers)代表船上有农夫和movers代表的东西if (safe(newlocation) && (route[newlocation] == -1)) //新状态安全且未处理{route[newlocation] = location; //记录新状态的前驱 enQueue_seq(moveTo, newlocation); //新状态入队}}}// 打印出路径if (route[15] != -1)//到达最终状态{printf("The reverse path is : \n");for (location = 15; location >= 0; location = route[location]) {r[a]=location;a++;if (location == 0) break;}for(i=a-1;i>=0;i--){printf("%d ",r[i]);bin_print(r[i]);//用1表示北岸,0表示南岸,用四位二进制数的顺序依次表示农夫、狼、白菜、羊的位置if(r[i]==0) printf("开始\n");//0000else if(r[i]==1) printf(" 农夫独自返回南岸\n"); //0001else if(r[i]==2) printf(" 农夫带着羊返回南岸\n");//0010else if(r[i]==3) printf(" 白菜与羊共同在北岸,不安全\n"); //0011else if(r[i]==4) printf(" 只有狼在北岸,农夫独自返回南岸\n"); //0100else if(r[i]==5) printf(" 狼与羊共同在北岸,不安全\n");//0101else if(r[i]==6) printf(" 农夫独自返回南岸\n");//0110else if(r[i]==7) printf(" 狼、白菜和羊共同在北岸,不安全\n");// 0111else if(r[i]==8) printf(" 农夫独自去北岸\n");//1000else if(r[i]==9) printf(" 农夫把羊带到北岸\n");//1001else if(r[i]==10) printf(" 农夫把白菜带到北岸\n");//1010else if(r[i]==11) printf(" 农夫把白菜带到北岸\n");//1011else if(r[i]==12) printf(" 农夫把狼带到北岸\n");//1100else if(r[i]==13) printf(" 只有白菜在南岸\n");//1101else if(r[i]==14) printf(" 农夫把狼带到北岸\n");//1110else if(r[i]==15) printf(" 农夫把羊带到北岸\n");//1111 putchar('\n');}printf("\n");}elseprintf("No solution.\n");}。

农夫过河问题

农夫过河问题1. 题目描述:一个农夫带着一只狼,一只羊和一筐菜,欲从河的左岸坐船到右岸,由于船太小,农夫每次只能带一样东西过河,并且没有农夫看管的话,狼会吃掉羊,羊会吃菜。

设计一个方案,使农夫可以无损失的过河2. 题目分析:假设人、狼、菜、羊都在河岸a,要到b 河岸去。

题中的食物链关系为: 菜→羊→狼 所以,第一次人只能带羊到b 河岸; 回到a 时,人不能再将刚带过来的羊带回去,所以人是空手回到a 的; 在a 河岸,人有两个选择选择一:(1) 带狼到b,人再回到a 时,因为不能把狼和羊同时留下,所以只能带走羊;AA 羊 A B羊狼 菜 怎么办呢 B 羊 B 狼 菜 菜 狼(2) 再次回到a 后,人再到b 时,不能把羊和菜同时留下,所以只能带走菜; (3) 再次回到a 时,因为狼和菜可以同时留下,所以优先选择空手过河;到a 后发现只剩下羊,所以带羊过河。

选择二:(1) 带菜到b,人再回到a 时,因为不能把菜和羊同时留下,所以只能带走羊;(2) 再次回到a 后,人再到b 时,不能把羊和狼同时留下,所以只能带走狼;狼 羊 羊 A菜 B 羊 狼 A B 狼 AB 狼 AB 羊菜 菜 菜(3) 再次回到a 时,因为狼和菜可以同时留下,所以优先选择空手过河;到a 后发现只剩下羊,所以带羊过河。

解:用四元组S 表示状态,即S =(L ,J ,M ,N )其中L :农夫 J :狼 M :羊 N :菜用0表示在左岸岸,1表示在右岸,即S=(0,0,0,0) 目标G =(1,1,1,1)定义操作符L (i )表示农夫带东西到右岸:i=0 农夫自己到右岸;i=1 农夫带狼到右岸;i=2 农夫带羊到右岸;i=3 农夫带菜到右岸;定义操作符R (i )表示农夫带东西到左岸:i=0 农夫自己到左岸;i=1 农夫带狼到左岸;i=2 农夫带羊到左岸;i=3 农夫带菜到左岸;约束状态如下:(1,0,0,1)狼、羊在左岸;(1,1,0,0)羊、菜在左岸;(0,1,1,0)狼、羊在右岸;(0,0,1,1)羊、菜在右岸;(1,0,0,0)狼、羊、菜在左岸;(0,1,1,1)狼、羊、菜在右岸;羊 A B狼 菜。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2 )、 狼 和 羊 是 否 单 独 在 一 起 , 羊 和 白 菜 是 否 单 独 在 一 起 , 用 语 句 a[ferryTimes][1] != a[ferryTimes][3] && (a[ferryTimes][2] == a[ferryTimes][1] || a[ferryTimes][0] == a[ferryTimes][1])来实现;
cout<<"\t 农夫使三样东西平安过河方法为:"<<endl<<endl;
Ferry(0);
}
for (i = 0; i < ferryTimes; i++) {
if (a[i][3] == 0) {
cout<<"\t\t\t 载"<<name[b[i]]<<"到对岸"<<endl; } else {
cout<<"\t\t\t 载"<<name[b[i]]<<"回本岸"<<endl; } } cout<<endl; return; } //狼单独和羊在一起以及羊和白菜单独在一起的情况 if (a[ferryTimes][1] != a[ferryTimes][3] && (a[ferryTimes][2] == a[ferryTimes][1] || a[ferryTimes][0] == a[ferryTimes][1])) { return; }
3)、如果上两个条件都不满,则可执行运输的动作,但每次都应考虑,该运 输情况以前是否执行过(即两岸以及船上的东西以及各自位置和以前完全相同),
如果没被执行过,则可以保存此时四者各自的状态,并递归的进行下一次运载。
5、系统测试
6、经验总结
解决实际问题时,应先分析实际问题,找出实际问题的所有约束条件, 然后对问题进行数学模型的抽象化,抓主要因素,省去一些不需要的因素,将其 抽象为数学问题,然后再从整体上设计算法,搭建程序的框架,最后一步步完善 细节,这样做,会使本来毫无头绪的问题变得清晰起来。
7、参考文献
《C++程序设计》 《数据结构》 《算法设计与分析》
程序代码如下: #include <iostream> #include <stdlib.h> #include <string.h> using namespace std; const int MAXTIMES = 20; int a[MAXTIMES][4];//存放农夫,狼,羊,白菜的位置,用 0 表示本岸,1 表示对岸
2、需求分析
1)、农夫必须把狼,羊,白菜全部都载过河,且一次只能载一个; 2)、要求狼和羊不能单独在一起,羊和白菜也不能单独在一起,即要么羊单 独在河的一边,要么羊和农夫在一起。
3、系统概述设计
对于上述情况,可以将河的两岸抽象成成数学问题,即将河的本岸抽象成数 字‘0’,将对岸抽象成‘1’;且将狼,羊,白菜,农夫,分别抽象成数字‘0’, ‘1’,‘2’,‘3’。而用数组 a[i][j](取值只能为 0 和 1)表示第 i 次运载是,j (j=0,1,2,3。分别表示狼,羊,白菜,农夫)所在的位置。而用 b[i]表示第 i 次运载时船上运载的东西(因为农夫每次都必须在船上,所以不用记录,除非穿 上只有农夫一人)。
1、问题描述
从前,一个农夫带着一只狼,一只羊和一棵白菜要河(注意该狼被农夫训服了,但还会 吃羊)。他要将所有东西安全的带到河的对岸,不幸的是河边只有一条船,只能装下农夫和 他的一样东西,并且农夫必须每次都随船过,因为只有他能撑船。在无人看管的情况下,狼 要吃羊,羊要吃白菜,因此,农夫不能在河的某边岸上单独留下狼和羊,也不能单独留下羊 和白菜。那么农夫如何才能使三样东西平安过河呢?
} } //若没有出现,则将运载后抵达另一岸的结果记录下来,并进行下一次运载 for (i = 0; i <= 3; i++) {
b[ferryTimes] = i; a[ferryTimes + 1][0] = a[ferryTimes][0]; a[ferryTimes + 1][1] = a[ferryTimes][1]; a[ferryTimes + 1][2] = a[ferryTimes][2]; a[ferryTimes + 1][3] = 1 - a[ferryTimes][3];
//用于判断此种情况在前 searchTimes 次运载过程中是否已经出现过,若出现过则不用 记录
for (i = 0; i < ferryTimes; i++) {
for(int j = 0; j < 4; j++) {
if(a[ferryTimes][j] != a[i][j]) {
break; } } if(j == 4) { return;
如此一来,是否全部过河的问题就转化为判断 a[i][0],a[i][1],a[i][2], a[i][3]是否全为 1 了,即相加之和是否为 4 的问题了;而四者中的两者是否能 在一起的问题就转化它们各自的 a[i][j]是否相等的问题了。
4、系统详细设计
创建一个数组 a[MAXTIMES][4]用于存放农夫,狼,羊,白菜的位置,用 0 表示本岸,1 表示对岸 ;
if (a[ferryTimes][i] == a[ferryTimes][3]) {
a[ferryTimes + 1][i] = a[ferryTimes + 1][3]; Ferry(ferryTimes + 1); } } }
void main()
{
cout<<"\n
****************************************************************************\n";
char *name[] = {"狼", "羊", "白菜", "农夫自己"}; int b[MAXTIMES]; //用于存放狼,羊,白菜,农夫的编号; 0: 狼,1:羊,2:白菜,3:农夫
void Ferry(int ferryTimes) //ferryTimes 为渡河次数 {
int i; if (a[ferryTimes][0] + a[ferryTimes][1] + a[ferryTimes][2] + a[ferryTimes][3] == 4) //都到达 对岸 {
b[MAXTIMES]用于存放狼,羊,白菜,农夫的编号; 0: 狼,1:羊,2:白菜, 3:农夫;
编写一个递归函数 Ferry(int ferryTimes),其中 ferryTimes 为渡河次数, 在函数中,应考虑 3 个问题:
1 )、 用 a[ferryTimes][0] + a[ferryTimes][1] + a[ferryTimes][2] + a[ferryTimes][3] == 4 语句判断是否全部到达对岸,如果是,则直接输出结果, 否则,考虑第二个问题;
cout<<" **
------------------------
**\n";
cout<<" **
|
农夫过河问题
|
**; **
------------------------
**\n";
cout<<"
****************************************************************************\n";
相关文档
最新文档