农夫过河问题状态图及程序
农夫过河
农夫过河问题——程序设计(2009-06-05 13:38:22)标签:分类:一、问题需求分析一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。
他要把这些东西全部运到北岸。
问题是他面前只有一条小船,船小到只能容下他和一件物品,另外只有农夫能撑船。
另外,因为狼能吃羊,而羊爱吃白菜,所以农夫不能留下羊和白菜或者狼和羊单独在河的一边,自己离开。
请问农夫该采取什么方案才能将所有的东西运过河呢?二、算法选择求解这个问题的最简单的方法是一步一步进行试探,每一步都搜索所有可能的选择,对前一步合适的选择再考虑下一步的各种方案。
用计算机实现上述求解的搜索过程可以采用两种不同的策略:一种是广度优先(breadth_first) 搜索,另一种是深度优先(depth_first) 。
广度优先:u 广度优先的含义就是在搜索过程中总是首先搜索下面一步的所有可能状态,然后再进一步考虑更后面的各种情况。
u 要实现广度优先搜索,一般都采用队列作为辅助结构。
把下一步所有可能达到的状态都列举出来,放在这个队列中,然后顺序取出来分别进行处理,处理过程中把再下一步的状态放在队列里……。
u 由于队列的操作遵循先进先出的原则,在这个处理过程中,只有在前一步的所有情况都处理完后,才能开始后面一步各情况的处理。
三、算法的精化要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。
一个很方便的办法是用四位二进制数顺序分别表示农夫、狼、白菜和羊的位置。
例如用0表示农夫或者某东西在河的南岸,1表示在河的北岸。
因此整数5(其二进制表示为0101) 表示农夫和白菜在河的南岸,而狼和羊在北岸。
四、算法的实现完成了上面的准备工作,现在的问题变成:从初始状态二进制0000(全部在河的南岸) 出发,寻找一种全部由安全状态构成的状态序列,它以二进制1111(全部到达河的北岸) 为最终目标,并且在序列中的每一个状态都可以从前一状态通过农夫(可以带一样东西)划船过河的动作到达。
实习六-农夫过河问题
农夫过河问题一、需求分析1.问题描述:一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。
他要把这些东西全部运到北岸。
他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。
如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。
2.基本要求:(1)利用图的存储结构(2)图的搜索算法(3)求出农夫将所有的东西运过河的所有方案二、设计1. 设计思想(1)存储结构以邻接矩阵存储合理状态,用一个一维数组保存所有的方案;(2)主要算法基本思想人,狼,羊和白菜共有2的四次方16种状态(河岸的状态可由人的状态确定),去掉不允许出现的6种状态,10个状态对应矩阵的10个结点值,然后根据状态的连续改变初始化矩阵,接着就用递归的深度优先法搜索所有的路径,即求出过河的方案。
main2. 设计表示(1)函数调用关系图main→Judge→Initiate→DFS→Push→StackPop→Top→GetTop→printfpath→Ch(2)函数接口规格说明int Judge(int a,int b) //将16种状态通过a,b输入,去掉不允许的6种int GetTop(Path *path,int *m) //出栈int Push(Path *path,int m) //入栈int Top(Path *path ,int *m) //读出栈顶值void Initiate(AdjMGraph *G,int n)//邻接矩阵顶点数为n的邻接矩阵G的建立int DFS(AdjMGraph *G,Path *path,int x,int t) 图G中搜索的起始点为X,从t点开始搜索与x关联的顶点,搜索过的点入栈path。
int printfpath(Path *path) //复制出出栈path中所有值,用FA【】保存void Printf(AdjMGraph *G)//辅助:邻接矩阵输出,用于观察搜索的过程。
数据结构实验-农夫过河问题
农夫过河问题一、实验目的掌握广度优先搜索策略,并用队列求解农夫过河问题二、实验内容问题描述:一农夫带着一只狼,一只羊和一颗白菜,身处河的南岸,他要把这些东西全部运到北岸,遗憾的是他只有一只小船,小船只能容下他和一件物品。
这里只能是农夫来撑船,同时因为狼吃羊、羊吃白菜、所以农夫不能留下羊和狼或羊和白菜在河的一边,而自己离开;好在狼属肉食动物,不吃白菜。
农夫怎么才能把所有的东西安全运过河呢?实验要求如下:(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;}实验结果:四、实验总结。
农夫过河问题(C++编写)
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)、如果上两个条件都不满,则可执行运输的动作,但每次都应考虑,该运 输情况以前是否执行过(即两岸以及船上的东西以及各自位置和以前完全相同),
Python程序设计 第六课-顺序结构 初中生
PART/03 编程实现
1.用Farmer、Wolf、Sheep、Cabbage四个变量分别表示农夫、狼、 羊、白菜 2.每个对象只有两种状态:过河、未过河,分别表示为1,0 3.将每个对象初始状态赋值为0: Farmer=Wolf=Sheep=Cabbage=0 4.如果谁过河,就将该变量置为1;谁返回,就置为0 5.当农夫、狼、羊、白菜都过了河,所有变量为1时,程序结束
PART/03 方案一实现
PART/04 顺序结构程序设计
1.在此游戏中,每个步骤都是依次执行的,各个步骤不能打乱次序, 这就是顺序结构的程序设计。 2.在顺序结构的程序设计中,每条语句按先后顺序分别执行一次,没 有跳过的语句,也没有重复运行的语句。 3.顺序结构是程序设计的基本结构之一。
PART/05 做一做
添加注释
Farmer=Sheep=1 #第一次过河
print(“第一次过河:","Farmer=",Farmer,"Wolf=",Wolf,"Sheep=",Sheep,"Cabbage=",Cabbage)
双引号或单引号
逗号隔开
除了汉字,其他字符均在英文状态下
PART/05 做一做
请大家参考方案一的实现过程,用Python 实现方案二
第6课
顺序结构程序设计——农夫的难题
PART/01 农夫的难题
PART/02 方案一
第一次过河:农夫带羊过河 第二次过河:农夫单独返回 第三次过河:农夫带狼过河 第四次过河:农夫带羊返回 第五次过河:农夫带菜过河 第六次过河:农夫单独返河:农夫带羊过河 第二次过河:农夫单独返回 第三次过河:农夫带菜过河 第四次过河:农夫带羊返回 第五次过河:农夫带狼过河 第六次过河:农夫单独返回 第七次过河:农夫带羊过河
数据结构实验-农夫过河问题
农夫过河问题一、实验目的掌握广度优先搜索策略,并用队列求解农夫过河问题二、实验内容问题描述:一农夫带着一只狼,一只羊和一颗白菜,身处河的南岸,他要把这些东西全部运到北岸,遗憾的是他只有一只小船,小船只能容下他和一件物品。
这里只能是农夫来撑船,同时因为狼吃羊、羊吃白菜、所以农夫不能留下羊和狼或羊和白菜在河的一边,而自己离开;好在狼属肉食动物,不吃白菜。
农夫怎么才能把所有的东西安全运过河呢?实验要求如下:(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;}实验结果:四、实验总结。
农夫过河问题
农夫过河问题
一、先分析农夫过河的情景: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."将狼带回起始岸语句。
农夫过河问题的求解
//从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;
算法的描述
%s'%(x,y,z))
*
做一做
给定年份判断是否是闰年
输入数字判断是否是水仙花数
*
谢谢观赏
感谢聆听
Make Presentation much more fun
@WPS官方微博 @kingsoftwps
第四步:最后把羊带过河。
用流程图来描述农夫过河的过程
流程图:
准备过河 农夫和羊过河,放下羊 农夫回来带白菜过河,放下白菜 农夫把羊带回来,放下羊,再带狼过河,放下狼
农夫回来,带羊过河 结束
用流程图描述算法
流程图(flow chart)是描述我们进行某一项活动所遵 循顺序的一种图示方法。
水费计算
开始
皮试
开始
皮下注射 y=2.85*第一 级用水量 +5.5*第二级 用水量 等待15分钟 否 是否过敏 可以 注射
输入用水量X X是否小于 等于20 是
y=2.85*第一级用 水量 否
是
不能注射
输出水费 结束
*
结束
用计算机语言描述算法
Python
Dim a As Integer, b As Integer, c As Integer for x in range(1.20):
算法思想初探
8年级信息组
2018-09-15
1 算法的描述
*
算法的描述
农夫、狼、 羊、菜
算法的描述(用自然语言描述)
我们使用了语言描述解决问题的过程,这种方法称为自 然语言描述算法。
第一步:农夫把羊先带过河,自己返回。 第二步:再把白菜带过河,同时把羊带回来。
第三步:把羊放下,然后把狼带过河,自己回来。
for y in range(1,33):
农夫过河报告(最终版)
农夫过河报告(最终版).12.29Administrator组员:李琦、郑鸿飞、王琅辉、张育博这最起码是一个报告,虽然我摘要农夫过河问题是应用广度优先搜索和深度优先搜索的典型问题,但这里我们应用了简单的数组,通过层层筛选的手段也解决了同样的问题,其中用到了部分广度优先搜索的思想。
前言农夫过河问题描述:一个农夫带着—只狼、一只羊和—棵白菜,身处河的南岸。
他要把这些东西全部运到北岸。
他面前只有一条小船,船只能容下他和—件物品,另外只有农夫才能撑船。
如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。
请求出农夫将所有的东西运过河的方案。
正文1.问题抽象和数据组织农夫过河问题应该应用图的广度优先遍历或者深度优先遍历,但这里我们仅使用简单的线性表——数组,通过多重的条件限制,达成目的。
这里我们同样用0和1代表农夫、狼、羊、白菜在左岸还是在右岸,并规定0在左,1在右,我们的目的便是从0000通过一系列变换到1111。
2.农夫过河算法源代码#include <stdio.h>#define MAX 16typedef struct FWSV{i nt farmer;i nt wolf;i nt sheep;i nt vegetable;}Item;//函数原型//操作:筛选符合条件的安全的数组成员//操作前:无//操作后:返回安全数组的指针void screen(void);//操作:判断下一个数应该取安全数组中那个数//操作前: 传递一个结构体数组成员//操作后:返回另一个结构体数组指针Item * judge(Item Fwsv);Item safe[MAX];int k = 0; //用于计数safe[]中的总数int main (void){s creen();I tem * next;I tem first,second,end;f irst = safe[0];e nd = safe[k];p rintf("first:0000\n");n ext = judge(first);for (int count = 0;count <= 6;count++){if (next->farmer + next->wolf + next->sheep + next->vegetable != 0){second = *next;next = judge(second);}elsenext++;}printf("end:1111\n");r eturn 0;}void screen(void){i nt f = 0,w = 0,s = 0,v = 0;f or(f = 0;f < 2;f++){for(w = 0;w < 2;w++){for(s = 0;s < 2;s++){for(v = 0;v < 2;v++){if (!(f != s && (s == w || s == v))){safe[k].farmer = f;s afe[k].wolf = w;s afe[k].sheep = s;safe[k].vegetable = v;k++;}}}}}}Item * judge(Item Fwsv){I tem * next;Item compare[4];n ext = compare;i nt x1 = 0;i nt sum = 0;i f (Fwsv.farmer == 0){for (int x = 0;x < k;x++){//把出现过的置零操作if(safe[x].farmer == Fwsv.farmer && safe[x].wolf == Fwsv.wolf && safe[x].sheep == Fwsv.sheep && safe[x].vegetable == Fwsv.vegetable ){safe[x].farmer = 0;safe[x].wolf = 0;safe[x].sheep = 0;safe[x].vegetable = 0;}//筛选出农夫状态值与之前相反的1变0 0变1if(safe[x].farmer == 1 && (safe[x].farmer + safe[x].wolf + safe[x].sheep + safe[x].vegetable != 4 )) {compare[x1] = safe[x];x1++;}}for (int x2 = 0;x2 < 4;x2++){//删除状态值与农夫不同但是改变了的sum = Fwsv.farmer + Fwsv.wolf + Fwsv.sheep + Fwsv.vegetable;if ((Fwsv.farmer != Fwsv.wolf && compare[x2].wolf != Fwsv.wolf)||(Fwsv.farmer != Fwsv.sheep && compare[x2].sheep != Fwsv.sheep)|| (Fwsv.farmer != Fwsv.vegetable && compare[x2].vegetable != Fwsv.vegetable)|| (Fwsv.farmer != Fwsv.vegetable && compare[x2].vegetable != Fwsv.vegetable)){compare[x2].farmer = 0;compare[x2].wolf = 0;compare[x2].sheep = 0;compare[x2].vegetable = 0;}sum+=2;//对和的限制if(compare[x2].farmer + compare[x2].wolf + compare[x2].sheep + compare[x2].vegetable != sum){compare[x2].farmer = 0;compare[x2].wolf = 0;compare[x2].sheep = 0;compare[x2].vegetable = 0;}}printf("-----------------------------------------\n");for(int x3 = 0;x3 < 4;x3++){if (compare[x3].farmer + compare[x3].wolf + compare[x3].sheep + compare[x3].vegetable != 0){printf("上数与:%d%d%d%d相连\n",c ompare[x3].farmer,compare[x3].wolf,c ompare[x3].sheep,compare[x3].vegetabl );}}}i f (Fwsv.farmer == 1){for (int y = 0;y < k;y++){if(safe[y].farmer == Fwsv.farmer && safe[y].wolf == Fwsv.wolf && safe[y].sheep == Fwsv.sheep && safe[y].vegetable == Fwsv.vegetable ){safe[y].farmer = 0;safe[y].wolf = 0;safe[y].sheep = 0;safe[y].vegetable = 0;}if(safe[y].farmer == 0 && (safe[y].farmer + safe[y].wolf + safe[y].sheep + safe[y].vegetable != 0 )) {compare[x1] = safe[y];x1++;}}for (int x2 = 0;x2 < 4;x2++){sum = Fwsv.farmer + Fwsv.wolf + Fwsv.sheep + Fwsv.vegetable;if ((Fwsv.farmer != Fwsv.wolf && compare[x2].wolf != Fwsv.wolf)||(Fwsv.farmer != Fwsv.sheep && compare[x2].sheep != Fwsv.sheep)|| (Fwsv.farmer != Fwsv.vegetable && compare[x2].vegetable != Fwsv.vegetable)|| (Fwsv.farmer != Fwsv.vegetable && compare[x2].vegetable != Fwsv.vegetable)){compare[x2].farmer = 0;compare[x2].wolf = 0;compare[x2].sheep = 0;compare[x2].vegetable = 0;}}printf("-----------------------------------------\n");for(int x3 = 0;x3 < 4;x3++){if (compare[x3].farmer + compare[x3].wolf + compare[x3].sheep + compare[x3].vegetable != 0){printf("上数与:%d%d%d%d相连\n",compare[x3].farmer,compare[x3].wolf,com pare[x3].sheep,compare[x3].vegetable );}}r eturn next;}3.算法功能说明和流程描述首先我们定义了一个结构体Itemtypedef struct FWSV{int farmer;int wolf;int sheep;int vegetable;}Item;Item中包含了农夫(farmer),狼(wolf),羊(sheep),白菜(vegetable),用来表示农夫、狼、羊、白菜的状态,并作出规定当为0的时候表示在左岸,当为1的时候表示在右岸,我们的目标便是从0000的状态到1111的状态。
农夫携物过河程序
题目内容:有一农夫要将自己的羊、蔬菜和狼等3件物品运过河。
但农夫过河时所用的船每次最多只能装英中的一件物品,而这3件物品之间又存在一左的制约关系:羊不能单独和狼以及不能和蔬菜在一起,因为狼要吃羊,羊也能吃蔬菜。
试构造出问题模式以编程实现这一问题的求解。
1、问题分析和任务定义:根据对象的状态分为过河(1)和不过河(0),此对象集合就构成了一个状态空间。
问题就是在这个状态空间内搜索一条从开始状态到结束状态的安全路径。
显然,其初始状态为四对象都不过河,结束状态为四对象全部过河。
这里用无向图来处理,并采用邻接矩阵存储。
对于农夫,狼,羊,蔬菜组成一个4位向量,即图的顶点(F,叭S, V),状态空间为16, 初始状态为(0000),目标为(1111)。
解决问题的方法是,找到所有的安全状态,并在其中搜索岀一条(0000)到(1111)的路径。
对当前对象是否安全的判断,若当农夫与羊不在一起时,狼与羊或羊与蔬菜在一起是不安全的,英他情况是安全的。
搜索一条可行路径时,采用深度优先搜索DFS_path,每个时刻探索一条路径,并记录访问过的合法状态,一直向前探视,直到疋不通时回溯。
显然,应该用数组来保存访问过的状态,以便回溯。
显然农夫每次状态都在改变,最多也就能带一件东西过河,故搜索条件是,在顶点(F, W, S, V)的转换中,狼,羊,蔬菜三者的状态不能大于一个,即只有一个发生改变或者都不变。
①数拯的输入形式和输入值的范用:本程序不需要输入数据,故不存在输入形式和输入值的范用。
②结果的输出形式:在屏幕上显示安全状态的转换,即一条安全路径。
2、数据结构的选择概要设计⑴数据结构的选择:本程序采用无向图处理。
#define MaxNumVertices 10 //最大顶点数typedef struct //图的顶点类型int Farmer, Wolf, Sheep, Veget; //存储农夫,狼,羊,蔬菜的状态}VexType;typedef struct//图的各项信息VexType VerticesList LMaxNumVertices]; //顶点向量(代表顶点)int Edge [MaxNumVertices] [MaxNumVertices];//邻接矩阵//用于存储图中的边,苴矩阵元素个数取决于顶点个数,与边数无关}AdjGraph;⑵为了实现上述程序的功能,需要:①生成所有安全的图的顶点:②査找顶点的位置:③判断目前(F, W. S, V)是否安全,安全返回1,否则返回0:④判断顶点i和顶点j之间是否可转换,可转换返回真,否则假:⑤深度优先搜索从u到v的简单路径; ⑥输出从u 到v的简单路径,即顶点序列中不重复出现的路径。
农夫过河问题状态空间表示
逻辑学教授的3个得意门生ABC,前一晚在酒吧喝多了,结果第二天3人集体迟到。
教授说:“作为对你们迟到的惩罚,你们3人必须比其他同学多做一道作业,完成了这道作业才可以离开教室。
”这道附加的作业是一道帽子题,教授给每人戴了顶帽子,帽子不是红色就是白色,不是白色就是红色。
每人都能看见其他2人帽子的颜色,却不能看见自己帽子的颜色。
每人都看到其他2人帽子的颜色后,每思考5分钟为一轮,谁猜出自己帽子的颜色了就可以说出来并离开。
教授还说:“你们3人中至少有1人戴了红色帽子。
”第一轮下来,A说:“我没猜出来。
”B说“我也没猜出来”C说:“我也猜不出。
”第二轮下来,还是没人能猜出自己帽子的颜色。
第三轮,3人都猜出了自己帽子的颜色。
问:ABC三人头顶都是什么颜色的帽子?然后用谓词逻辑写出推理过程。
最一般合一及归结反演相关已知w={P(f(x,g(A,y)),z), P(f(x,z),z),求MGU令δ0=ε,w0=w,因w中含有两个表达式,因此δ0不是最一般合一差异集D0={g(A,y)/z}δ1=δ0ºD0={g(A,y)/z}w1={P(f(x,g(A,y)),g(A,y)), P(f(x,g(A,y)),g(A,y))w1中仅含有一个表达式,所以δ1就是最一般合一。
证明G是否是F1、F2的逻辑结论。
F1:(∀x)(P(x)→(Q(x)∧R(x)))F2:(∃x)(P(x)∧S(x))G: (∃x)(S(x)∧R(x))F1: ¬P(x)∨(Q(x)∧R(x)) ⇒(¬P(x)∨Q(x)) ∧(¬P(x)∨R(x))F2: P(x)∧S(x)¬G: ¬(∃x)(S(x)∧R(x)) ⇒ (∀x)(¬(S(x)∧R(x))) ⇒¬S(x)∨¬R(x)子句集:1 ¬P(x)∨Q(x)2 ¬P(x)∨R(x)3 P(x)4 S(x)5 ¬S(x)∨¬R(x)其中2与3规约,4与5归结,其结果再归结得到空子句,证明G是F1与F2的结论。
农夫过河数据结构
农夫过河数据结构郑州轻工业学院课程设计任务书题目农夫过河专业、班级计算机科学与技术学号姓名主要内容:一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸,要把这些东西全部运到北岸。
他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。
如果农夫在场,则狼不能吃羊,羊不能吃白菜;否则狼会吃羊,羊会吃白菜。
所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不能吃白菜。
要求给出农夫将所有的东西运过河的方案。
基本要求:编写求解该问题的算法程序,并用此程序上机运行、调试,屏幕显示结果,能结合程序进行分析。
主要参考资料:数据结构严蔚敏完成期限: 2012/6/21指导教师签名:课程负责人签名:年月日郑州轻工业学院本科数据结构课程设计总结报告设计题目:农夫过河学生姓名:系别:计算机与通信工程学院专业:计算机科学与技术班级:计算机科学与技术学号:指导教师:2012年 6 月 21 日2一,设计题目问题描述:一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸,他要把这些东西全部运到北岸。
他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。
如果农夫在场,则狼不能吃羊,羊不能吃白菜;否则狼会吃羊,羊会吃白菜。
所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不能吃白菜。
要求给出农夫将所有的东西运过河的方案。
二,运行环境(软、硬件环境)VC6.0 Windows7系统三,算法设计的思想对于这个问题,我们需要先自动生成图的邻接矩阵来存储,主要方法是先生成各种安全状态结点,存放在顶点向量中;再根据判断两个结点间状态是否可以转换来形成顶点之间的所有边,并把它们保存在邻接矩阵中。
在建立了图的邻接矩阵存储结构后,利用递归深度优先搜索求出从顶点(0,0,0,0)到顶点(1,1,1,1)的一条简单路径,这样做只能搜到一种合理方法,因为深度优先搜索遍历一个图的时候每一个结点只能被访问一次。
农夫过河问题状态图及程序
农夫过河问题状态图及程序一、问题需求分析一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。
他要把这些东西全部运到北岸。
问题是他面前只有一条小船,船小到只能容下他和一件物品,另外只有农夫能撑船。
另外,因为狼能吃羊,而羊爱吃白菜,所以农夫不能留下羊和白菜或者狼和羊单独在河的一边,自己离开。
请问农夫该采取什么方案才能将所有的东西运过河呢?二、算法选择求解这个问题的最简单的方法是一步一步进行试探,每一步都搜索所有可能的选择,对前一步合适的选择再考虑下一步的各种方案。
用计算机实现上述求解的搜索过程可以采用两种不同的策略:一种是广度优先(breadth_first) 搜索,另一种是深度优先(depth_first) 。
广度优先:u 广度优先的含义就是在搜索过程中总是首先搜索下面一步的所有可能状态,然后再进一步考虑更后面的各种情况。
u 要实现广度优先搜索,一般都采用队列作为辅助结构。
把下一步所有可能达到的状态都列举出来,放在这个队列中,然后顺序取出来分别进行处理,处理过程中把再下一步的状态放在队列里……。
u 由于队列的操作遵循先进先出的原则,在这个处理过程中,只有在前一步的所有情况都处理完后,才能开始后面一步各情况的处理。
三、算法的精化要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。
一个很方便的办法是用四位二进制数顺序分别表示农夫、狼、白菜和羊的位置。
例如用0表示农夫或者某东西在河的南岸,1表示在河的北岸。
因此整数5(其二进制表示为0101) 表示农夫和白菜在河的南岸,而狼和羊在北岸。
四、算法的实现完成了上面的准备工作,现在的问题变成:从初始状态二进制0000(全部在河的南岸) 出发,寻找一种全部由安全状态构成的状态序列,它以二进制1111(全部到达河的北岸) 为最终目标,并且在序列中的每一个状态都可以从前一状态通过农夫(可以带一样东西)划船过河的动作到达。
为避免不必要的瞎费功夫,要求在序列中不应该出现重复的状态。
农夫过河问题
一:问题描述设一个农夫过河带着一条狼、一只羊和一棵白菜,身处河的南岸。
现在他要把这些西全部运到北岸,现在问题是他面前只有一条小船,船小到只能容下他和一件物品,另外只有农夫能撑船。
当农夫在场的时候,这三样东西相安无事.一旦农夫不在,狼会吃羊,羊会吃白菜。
根据原题的描述我们知道,单独留下白菜和羊,或单独留下狼和羊在某一岸的状态是不安全的。
白菜和狼相处没事,把它看作个重要关系的,通过位置分布的代码来判断状态是否安全。
然后设计一个方案, 模拟农夫能安全地将这三样东西带过河。
二、设计思路利用图论知识求解的过程。
假设分别用farmer表示农夫,wolf表示狼,sheep 表示羊,veget表示白菜。
初始状态是f、w、s、v都在原岸,即初始状态V1为={f,w,s,v},在原岸全部可能出现的状态为以下16种:fwsv、fwv、fsv、wsv、fw、fs、fv、ws、wv、sv、f、w、s、v、φ,这里φ表示原岸是空集,即人、狼、羊、白菜都已运到河的对岸去了。
根据题意可以得到,这16种情况中有6种情况是不允许出现的。
它们是:wsv(狼、羊、白菜)、fw(农夫、狼)、fv(农夫、白菜)、ws(狼、羊)、sv (羊、白菜)、f(农夫)。
如fv表示人和白菜在原岸,而狼和羊在对岸,这显然是不行的。
因此,允许出现的情况只有10种。
我们构造一个图,它的顶点就是这10种状态。
如果船某次从河的一岸划往另一岸时,使原岸的状态从V变成V’,我们就作一条从V到V’的弧,这样就可以得到如下图所示的有向图人狼羊白菜人狼人狼白菜人羊白菜人羊●●●●●●●●●●狼白菜狼草羊空由于船是在两岸间往返的,那么“过河”问题就转换成在上图中找出一条由结点fwsv到结点φ的路径,这条路径中相邻的两条弧或者都是由同一点引出的,或者都是进入同一个结点的,这样的路径是很容易找到的。
从图中得到两条这样的路径,路径一:人狼羊白菜→狼白菜→人狼白菜→白菜→人羊白菜→羊→人羊→φ,路径二:人狼羊白菜→狼白菜→人狼白菜→狼→人狼羊→羊→人羊→φ,它们的长度都是7,也就是说,农夫至少要经过7次摆渡才能将狼、羊、白菜都安全摆渡到对岸,可以有两种方案。
农夫过河报告(最终版)
农夫过河算法实验报告组长:崔俊组员:李琦、郑鸿飞、王琅辉、张育博15.12.29摘要农夫过河问题是应用广度优先搜索和深度优先搜索的典型问题,但这里我们应用了简单的数组,通过层层筛选的手段也解决了同样的问题,其中用到了部分广度优先搜索的思想。
前言农夫过河问题描述:一个农夫带着—只狼、一只羊和—棵白菜,身处河的南岸。
他要把这些东西全部运到北岸。
他面前只有一条小船,船只能容下他和—件物品,另外只有农夫才能撑船。
如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。
请求出农夫将所有的东西运过河的方案。
正文1.问题抽象和数据组织农夫过河问题应该应用图的广度优先遍历或者深度优先遍历,但这里我们仅使用简单的线性表——数组,通过多重的条件限制,达成目的。
这里我们同样用0和1代表农夫、狼、羊、白菜在左岸还是在右岸,并规定0在左,1在右,我们的目的便是从0000通过一系列变换到1111。
2.农夫过河算法源代码#include <stdio.h>#define MAX 16typedef struct FWSV{int farmer;int wolf;int sheep;int vegetable;}Item;//函数原型//操作:筛选符合条件的安全的数组成员//操作前:无//操作后:返回安全数组的指针void screen(void);//操作:判断下一个数应该取安全数组中那个数//操作前: 传递一个结构体数组成员//操作后:返回另一个结构体数组指针Item * judge(Item Fwsv);Item safe[MAX];int k = 0; //用于计数safe[]中的总数int main (void){screen();Item * next;Item first,second,end;first = safe[0];end = safe[k];printf("first:0000\n");next = judge(first);for (int count = 0;count <= 6;count++){if (next->farmer + next->wolf + next->sheep + next->vegetable != 0){second = *next;next = judge(second);}elsenext++;}printf("end:1111\n");return 0;}void screen(void){int f = 0,w = 0,s = 0,v = 0;for(f = 0;f < 2;f++){for(w = 0;w < 2;w++){for(s = 0;s < 2;s++){for(v = 0;v < 2;v++){if (!(f != s && (s == w || s == v))){safe[k].farmer = f;safe[k].wolf = w;safe[k].sheep = s;safe[k].vegetable = v;k++;}}}}}}Item * judge(Item Fwsv){Item * next;Item compare[4];next = compare;int x1 = 0;int sum = 0;if (Fwsv.farmer == 0){for (int x = 0;x < k;x++){//把出现过的置零操作if(safe[x].farmer == Fwsv.farmer && safe[x].wolf == Fwsv.wolf && safe[x].sheep == Fwsv.sheep && safe[x].vegetable == Fwsv.vegetable ){safe[x].farmer = 0;safe[x].wolf = 0;safe[x].sheep = 0;safe[x].vegetable = 0;}//筛选出农夫状态值与之前相反的 1变0 0变1if(safe[x].farmer == 1 && (safe[x].farmer + safe[x].wolf + safe[x].sheep + safe[x].vegetable != 4 )){compare[x1] = safe[x];x1++;}}for (int x2 = 0;x2 < 4;x2++){//删除状态值与农夫不同但是改变了的sum = Fwsv.farmer + Fwsv.wolf + Fwsv.sheep + Fwsv.vegetable;if ((Fwsv.farmer != Fwsv.wolf && compare[x2].wolf != Fwsv.wolf) ||(Fwsv.farmer != Fwsv.sheep && compare[x2].sheep != Fwsv.sheep)|| (Fwsv.farmer != Fwsv.vegetable && compare[x2].vegetable != Fwsv.vegetable)|| (Fwsv.farmer != Fwsv.vegetable && compare[x2].vegetable != Fwsv.vegetable)){compare[x2].farmer = 0;compare[x2].wolf = 0;compare[x2].sheep = 0;compare[x2].vegetable = 0;}sum+=2;//对和的限制if(compare[x2].farmer + compare[x2].wolf + compare[x2].sheep + compare[x2].vegetable != sum){compare[x2].farmer = 0;compare[x2].wolf = 0;compare[x2].sheep = 0;compare[x2].vegetable = 0;}}printf("-----------------------------------------\n");for(int x3 = 0;x3 < 4;x3++){if (compare[x3].farmer + compare[x3].wolf + compare[x3].sheep + compare[x3].vegetable != 0){printf("上数与:%d%d%d%d相连\n",compare[x3].farmer,compare[x3].wolf,compare[x3].sheep,compare[x3].veget abl );}}}if (Fwsv.farmer == 1){for (int y = 0;y < k;y++){if(safe[y].farmer == Fwsv.farmer && safe[y].wolf == Fwsv.wolf && safe[y].sheep == Fwsv.sheep && safe[y].vegetable == Fwsv.vegetable ){safe[y].farmer = 0;safe[y].wolf = 0;safe[y].sheep = 0;safe[y].vegetable = 0;}if(safe[y].farmer == 0 && (safe[y].farmer + safe[y].wolf + safe[y].sheep + safe[y].vegetable != 0 )){compare[x1] = safe[y];x1++;}}for (int x2 = 0;x2 < 4;x2++){sum = Fwsv.farmer + Fwsv.wolf + Fwsv.sheep + Fwsv.vegetable;if ((Fwsv.farmer != Fwsv.wolf && compare[x2].wolf != Fwsv.wolf) ||(Fwsv.farmer != Fwsv.sheep && compare[x2].sheep != Fwsv.sheep)|| (Fwsv.farmer != Fwsv.vegetable && compare[x2].vegetable != Fwsv.vegetable)|| (Fwsv.farmer != Fwsv.vegetable && compare[x2].vegetable != Fwsv.vegetable)){compare[x2].farmer = 0;compare[x2].wolf = 0;compare[x2].sheep = 0;compare[x2].vegetable = 0;}}printf("-----------------------------------------\n");for(int x3 = 0;x3 < 4;x3++){if (compare[x3].farmer + compare[x3].wolf + compare[x3].sheep + compare[x3].vegetable != 0){printf("上数与:%d%d%d%d相连\n",compare[x3].farmer,compare[x3].wolf,compare[x3].sheep,compare[x3].vegetable );}}}return next;}3.算法功能说明和流程描述首先我们定义了一个结构体Itemtypedef struct FWSV{int farmer;int wolf;int sheep;int vegetable;}Item;Item中包含了农夫(farmer),狼(wolf),羊(sheep),白菜(vegetable),用来表示农夫、狼、羊、白菜的状态,并作出规定当为0的时候表示在左岸,当为1的时候表示在右岸,我们的目标便是从0000的状态到1111的状态。
农夫过河问题算法设计与实现
农夫过河问题算法设计与实现咱来唠唠农夫过河这个有趣的问题。
一、问题描述农夫要带着一只狼、一只羊和一棵白菜过河。
但是呢,船很小,每次农夫只能带一样东西过河。
而且啊,如果农夫不在,狼会吃羊,羊会吃白菜,这可就麻烦大了。
二、算法设计思路1. 初始状态- 河这边有农夫、狼、羊和白菜,河对岸啥都没有。
2. 第一步很关键- 农夫肯定不能先带狼或者白菜,为啥呢?因为如果先带狼过去,把羊和白菜留在这边,羊就会吃白菜;要是先带白菜过去,狼就会吃羊。
所以农夫得先带羊过河。
- 然后农夫自己返回。
这时候河这边有狼和白菜,河对岸有羊。
3. 第二步- 农夫再带狼或者白菜过河。
假设农夫带狼过河吧。
- 但是农夫不能把羊单独留在对岸啊,所以农夫得把羊再带回来。
这时候河这边有羊和白菜,河对岸有狼。
4. 第三步- 农夫把羊放下,带白菜过河。
- 然后农夫自己返回。
这时候河这边有羊,河对岸有狼和白菜。
5. 最后一步- 农夫再带羊过河,这样就都安全地到对岸啦。
三、算法实现(用简单的文字描述过程)1. 开始:- 农夫在起始岸,物品(狼、羊、白菜)也在起始岸,对岸为空。
2. 第一次过河:- 农夫带羊过河,此时起始岸有狼和白菜,对岸有羊和农夫。
- 农夫独自返回起始岸,此时起始岸有农夫、狼、白菜,对岸有羊。
3. 第二次过河:- 农夫带狼过河,此时起始岸有白菜,对岸有狼、羊和农夫。
- 农夫带羊返回起始岸,此时起始岸有农夫、羊、白菜,对岸有狼。
4. 第三次过河:- 农夫带白菜过河,此时起始岸有羊,对岸有狼、白菜和农夫。
- 农夫独自返回起始岸,此时起始岸有农夫、羊,对岸有狼、白菜。
5. 第四次过河:- 农夫带羊过河,此时起始岸为空,对岸有农夫、狼、羊、白菜,大功告成!你看,这样一步一步的,就像走迷宫一样,按照规则走,就能让农夫带着他的东西安全过河啦。
1.1算法与程序框图
结束
开始
输入a,b,c
b2 4ac
0? 否
是
p b 2a
q 2a
输出“方程没 有实数根”
练习2:设计一个求任意数的绝对值的算法,并画
出程序框图.
程序框图:
x(当x 0时) | x | x(当x<0时)
开始
算法分析:
输入x
第一步:输入数x;
知识探究(一):算法的程序框图 思考1:“判断整数n(n>2)是否为质数”的 算法步骤如何? 第一步,给定一个大于2的整数n; 第二步,令i=2; 第三步,用i除n,得到余数r;
第四步,判断“r=0”是否成立.若是,则n 不是质数,结束算法;否则,将i 的值增加1,仍用i表示;
第五步,判断“i>(n-1)”是否成立,若是, 则n是质数,结束算法;否则,返回 第三步.
(1)必须有两个起止框,穿插输入、输 出框和处理框,没有判断框.
(2)各程序框从上到下用流程线依次 连接.
(3)处理框按计算机执行顺序沿流程线 依次排列.
知识探究(三):算法的条件结构
条件结构
否
r=0?
是
N不是质数
n是质数
条件结构---在一个算法中,经常会遇到一些 条件的判断,算法的流向根据条件是否成立 有不同的流向.条件结构就是处理这种过程 的结构.
赋值、计算
判断某一条件是否成立,成立 时在出口处标明“是”或 “Y”;不”成立时标明“否”
或连“N接”.程序框
连接点 连接程序框图的两部分
一般用i=i+1 表示.
开始 输入n i=2
设n是一个大 于2的整数.
求n除以i的余数r
说明:i表示从2~(n-1) 的所有正整数,用以
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
农夫过河问题状态图及程序一、问题需求分析一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。
他要把这些东西全部运到北岸。
问题是他面前只有一条小船,船小到只能容下他和一件物品,另外只有农夫能撑船。
另外,因为狼能吃羊,而羊爱吃白菜,所以农夫不能留下羊和白菜或者狼和羊单独在河的一边,自己离开。
请问农夫该采取什么方案才能将所有的东西运过河呢?二、算法选择求解这个问题的最简单的方法是一步一步进行试探,每一步都搜索所有可能的选择,对前一步合适的选择再考虑下一步的各种方案。
用计算机实现上述求解的搜索过程可以采用两种不同的策略:一种是广度优先(breadth_first) 搜索,另一种是深度优先(depth_first) 。
广度优先:u 广度优先的含义就是在搜索过程中总是首先搜索下面一步的所有可能状态,然后再进一步考虑更后面的各种情况。
u 要实现广度优先搜索,一般都采用队列作为辅助结构。
把下一步所有可能达到的状态都列举出来,放在这个队列中,然后顺序取出来分别进行处理,处理过程中把再下一步的状态放在队列里……。
u 由于队列的操作遵循先进先出的原则,在这个处理过程中,只有在前一步的所有情况都处理完后,才能开始后面一步各情况的处理。
三、算法的精化要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。
一个很方便的办法是用四位二进制数顺序分别表示农夫、狼、白菜和羊的位置。
例如用0表示农夫或者某东西在河的南岸,1表示在河的北岸。
因此整数5(其二进制表示为0101) 表示农夫和白菜在河的南岸,而狼和羊在北岸。
四、算法的实现完成了上面的准备工作,现在的问题变成:从初始状态二进制0000(全部在河的南岸) 出发,寻找一种全部由安全状态构成的状态序列,它以二进制1111(全部到达河的北岸) 为最终目标,并且在序列中的每一个状态都可以从前一状态通过农夫(可以带一样东西)划船过河的动作到达。
为避免不必要的瞎费功夫,要求在序列中不应该出现重复的状态。
为了实现广度优先搜索,算法中需要使用了一个整数队列moveTo,它的每个元素表示一个可以安全到达的中间状态。
另外还需要一个数据结构记录已被访问过的各个状态,以已被发现的能够到达当前这个状态的路径。
由于在这个问题的解决过程中需要列举的所有状态(二进制0000 ~ 1111)一共16种,所以可以构造一个包含16个元素的整数顺序表来满足以上的要求。
用顺序表的第i个元素记录状态i是否已被访问过,若已被访问过则在这个顺序表元素中记入前驱状态值,算法中把这个顺序表叫做route。
route 的每个分量初始化值均为-1,每当我们在队列中加入一个新状态时,就把顺序表中以该状态作下标的元素的值改为达到这个状态的路径上前一状态的下标值。
route的一个元素具有非负值表示这个状态已访问过,或是正被考虑。
最后我们可以利用route顺序表元素的值建立起正确的状态路径。
五、代码// farmerProblem.c// 用队列解决农夫过河问题#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)// 在队尾插入元素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){//判断农夫的位置return (0 != (location &0x08));}int wolf(int location){//判断狼的位置return (0 != (location &0x04)); }int cabbage(int location){//判断白菜的位置return (0 != (location &0x02)); }int goat(int location){//判断羊的位置return (0 != (location &0x01)); }//安全状态的判断函数int safe(int location){// 若状态安全则返回trueif ((goat(location) == cabbage(location)) &&(goat(location) != farmer(location)))return (0);// 羊吃白菜if ((goat(location) == wolf(location)) && (goat(location) != farmer(location)))return (0);// 狼吃羊return (1); // 其他状态是安全的}main(){int i, movers, location, newlocation;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); //计算新状态 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]){printf("The location is : %d\n", location);if (location == 0)exit(0);}}elseprintf("No solution.\n");//问题无解}六、测试结果输出按相反的变化方向输出的,真实的情况应该是从0、9、……、15变化的。
七、总结和体会这个还有很大的改进空间,首先是人性化方面的设计,这个最终的输出结果是用10进制的,而我们需要知道的应该是二进制的结果,所以应该直接把结果输出为二进制,还要按开始到最终状态的排序输出。
还有一种更为人性化的设计,就是把对应的每个二进制代码代表的含义直接用中文表示出来,这样的结果更直观,方便用户使用。
例如:0000时,输出:所有的物品都在南岸。
后面的一个状态是9(1001),输出:农夫和羊到了北岸。
通过这个的学习,很受启发,明白了如何用计算机解决实际生活中的问题。
刚开始接到这个题目时,感觉到相当困难,因为这种题以前是考验我们的IQ用的,现在没想到要用计算机来解决,而且计算机又没有思想,怎样让它想问题,实现我们需要的功能。
原来,可以把实际的问题转变为数学模型,通过计算机超强悍的循环功能和强大的数据处理能力,把所有可能的结果都算出来,然后用约束项来对这些结果进行筛选,然后把结果用数学格式来输出,让问题得以求解。