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

农夫过河问题一、实验目的掌握广度优先搜索策略,并用队列求解农夫过河问题二、实验内容问题描述:一农夫带着一只狼,一只羊和一颗白菜,身处河的南岸,他要把这些东西全部运到北岸,遗憾的是他只有一只小船,小船只能容下他和一件物品。
这里只能是农夫来撑船,同时因为狼吃羊、羊吃白菜、所以农夫不能留下羊和狼或羊和白菜在河的一边,而自己离开;好在狼属肉食动物,不吃白菜。
农夫怎么才能把所有的东西安全运过河呢?实验要求如下:(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. 培养学生的观察、分析、总结能力。
二、实验原理动物行为学是研究动物在自然界中的行为规律和适应策略的学科。
通过观察小黄鸭过河的行为,可以了解其在不同环境下的适应能力,以及动物行为与环境因素之间的关系。
三、实验材料与工具1. 实验材料:小黄鸭、水桶、河岸、摄像机、记录表等。
2. 实验工具:摄像机、录音笔、计时器等。
四、实验方法1. 实验分组:将小黄鸭分为实验组和对照组,实验组过河,对照组在河岸观察。
2. 实验步骤:(1)将小黄鸭放入水桶中,观察其在水中的行为;(2)将水桶移至河岸,模拟小黄鸭过河的过程;(3)记录小黄鸭过河的时间、速度、路线等行为特点;(4)观察小黄鸭在过河过程中的适应能力,如游泳、潜水、攀爬等;(5)对实验数据进行统计分析。
五、实验结果与分析1. 实验结果(1)实验组小黄鸭过河的时间平均为10秒;(2)对照组小黄鸭在河岸观察的时间平均为15秒;(3)实验组小黄鸭在过河过程中,游泳、潜水、攀爬等行为均有出现。
2. 实验分析(1)实验组小黄鸭过河的时间较短,说明其具有较强的适应能力;(2)对照组小黄鸭在河岸观察的时间较长,说明其对过河环境不熟悉,适应能力较弱;(3)实验组小黄鸭在过河过程中,游泳、潜水、攀爬等行为的出现,表明其具有较强的适应环境的能力。
六、实验结论1. 小黄鸭在过河过程中具有较强的适应能力,能够通过游泳、潜水、攀爬等方式应对环境变化;2. 观察动物行为有助于了解其在自然界中的生存策略,为动物保护提供参考。
七、实验讨论1. 本实验结果表明,小黄鸭在过河过程中具有较好的适应能力,这与其在自然界中的生存环境密切相关;2. 实验过程中,对照组小黄鸭在河岸观察的时间较长,说明其在过河前需要一定的时间来熟悉环境,提高适应能力;3. 本实验为动物行为学研究提供了新的思路,有助于进一步了解动物在自然界中的生存策略。
青蛙过河实验报告总结

青蛙过河实验报告总结引言本实验旨在通过观察和记录青蛙在不同条件下过河的行为,探究青蛙在不同河流环境中的适应能力和行为模式。
通过实验,我们进一步了解了青蛙的特性和行为习惯,对生态学领域的研究和保护工作具有一定的参考意义。
实验方法实验使用的设备和材料包括:一条模拟河流,距离标记板,青蛙,记录表格等。
实验过程如下:1. 准备河流:在实验区域搭建模拟河流,确保河流的长度、水流速度和水深能在一定范围内进行调节。
在距离标记板上分别标注不同距离的刻度,用于测量青蛙从起点到达不同距离的时间。
2. 实验组设置:选取不同种类、不同个体的青蛙作为实验对象。
将青蛙放置在河流起点,记录青蛙从起点到达不同距离所花费的时间。
每组实验重复3次,取平均值作为结果数据。
3. 数据记录与分析:将实验过程中观察到的数据记录在表格中,包括青蛙种类、个体、距离和所需时间等信息。
通过对数据的分析和比较,得出相应的结论。
实验结果与讨论结果呈现在实验中,我们观察到不同种类的青蛙在通过模拟河流时表现出了不同的行为模式。
以下是我们得到的主要结果:1. 青蛙种类差异:我们选取了可跳跃类青蛙和游泳类青蛙作为实验对象,发现可跳跃类青蛙在通过短距离的水域时表现出较好的适应能力,而游泳类青蛙在长距离的水域中更加游刃有余。
2. 个体差异:在同一种类的青蛙中,不同个体之间也存在着差异。
有些青蛙表现出较好的跳跃能力或游泳能力,而有些则相对较差。
这种个体差异可能与青蛙体型大小、年龄和健康状况等因素相关。
3. 距离与时间关系:我们观察到青蛙在越短的距离内通过水域所需时间越短,而在较长的距离上则需要更多的时间。
这与跳跃和游泳所需的能量消耗以及行动的效率有关。
结果讨论通过以上结果的观察和分析,我们可以得出以下一些结论和讨论:1. 青蛙的适应能力:不同种类的青蛙在过河实验中表现出了不同的适应能力。
可跳跃类青蛙具有较好的腿力和跳跃能力,而游泳类青蛙则具备较好的水生适应能力。
这与它们在不同生态环境中的生活习惯和适应能力相吻合。
MC牧师过河问题

MC牧师过河问题⼈⼯智能上机实验报告学号:姓名:所在系:信息学院班级:实验名称:实验⽇期2016年12⽉3⽇实验指导教师实验机房A401------------------------------------------------------------------------------------------------------ 1.实验⽬的:(1)在掌握状态空间搜索策略的基础上,理解知识表⽰的⽅法。
(2)能够应⽤知识表⽰⽅法,解决实际问题2. 实验内容:(1)M-C问题描述有n个牧师和n个野⼈准备渡河,但只有⼀条能容纳c个⼈的⼩船,为了防⽌野⼈侵犯牧师,要求⽆论在何处,牧师的⼈数不得少于野⼈的⼈数(除⾮牧师⼈数为0),且假定野⼈与牧师都会划船,试设计⼀个算法,确定他们能否渡过河去,若能,则给出⼩船来回次数最少的最佳⽅案。
3.算法设计(编程思路或流程图或源代码)#include#include#include#define maxloop 100 /* 最⼤层数,对于不同的扩展⽅法⾃动调整取值*/#define pristnum 3 /*初始化时设定有3个野⼈3个牧师,实际可以改动*/#define slavenum 3struct SPQ{ int sr,pr; /* 船运⾏⼀个来回后河右岸的野⼈、牧师的⼈数*/int sl,pl; /* 船运⾏⼀个来回后河左岸的野⼈、牧师的⼈数*/int ssr,spr; /* 回来(由左向右时)船上的⼈数*/int sst,spt; /* 去时(由右向左时)船上的⼈数*/int loop; /* 本结点所在的层数*/struct SPQ *upnode ,*nextnode;/* 本结点的⽗结点和同层的下⼀个结点的地址*/}spq;int loopnum;/* 记录总的扩展次数*/int openednum;/* 记录已扩展节点个数*/int unopenednum;/* 记录待扩展节点个数*/int resultnum;struct SPQ *opened;struct SPQ *oend;struct SPQ *unopened;struct SPQ *uend;struct SPQ *result;void initiate();void releasemem();void showresult();void addtoopened(struct SPQ *ntx);int search();void goon();int stretch(struct SPQ* ntx);void recorder();void addtoopened(struct SPQ *ntx) /*扩展节点*/ { unopened = unopened -> nextnode; unopenednum--; if (openednum == 0 )oend = opened = ntx;oend -> nextnode = ntx;oend = ntx;openednum++;}void recorder(){int i , loop;struct SPQ *newnode;struct SPQ *ntx;loop = oend -> loop;ntx = oend;resultnum = 0;for( i = 0 ; i <= loop ; i++ ){newnode = (struct SPQ*) malloc (sizeof(spq));if(newnode==NULL){printf("\n内存不够!\n");exit(0);}newnode -> sr = ntx -> sr;newnode -> pr = ntx -> pr;newnode -> sl = ntx -> sl;newnode -> pl = ntx -> pl;newnode -> sst = ntx -> sst;newnode -> spt = ntx -> spt; newnode -> ssr = ntx -> ssr; newnode -> spr = ntx -> spr; newnode -> nextnode = NULL;ntx = ntx -> upnode;if(i == 0)result = newnode;newnode -> nextnode = result; result = newnode;resultnum++;}}void releasemem(){int i;struct SPQ* nodefree;for ( i = 1 ; i < openednum ; i++ ) {nodefree = opened;opened = opened -> nextnode;free(nodefree);}for ( i = 0 ; i < unopenednum ; i++ ) {nodefree = unopened;unopened = unopened -> nextnode; free(nodefree);}}void showresult() /*显⽰*/{int i;int fsr , fpr ; /* 在右岸上的⼈数*/ int fsl , fpl ; /* 在左岸上的⼈数*/ struct SPQ* nodefree;printf("%d个牧师",result -> pr); printf("%d个野⼈",result -> sr); printf("%d个牧师",result -> pl); printf("%d个野⼈",result -> sl); for ( i = 1 ; i < resultnum ; i++ ) {nodefree = result;result = result -> nextnode;free(nodefree);printf("\n\n\t左岸⼈数船上⼈数及⽅向右岸⼈数\n");printf("第%d轮\n",i);fpl = result -> pl - result -> spt + result -> spr;fpr = result -> pr - result -> spr;fsl = result -> sl - result -> sst + result -> ssr;fsr = result -> sr - result -> ssr;printf("牧师%8d%8d\t<-\t%8d\n",fpl,result -> spt,fpr);printf("野⼈%8d%8d\t<-\t%8d\n",fsl,result -> sst,fsr);printf("牧师%8d%8d\t->\t%8d\n",result -> pl,result -> spr,result -> pr - result -> spr); printf("野⼈%8d%8d\t->\t%8d\n",result -> sl,result -> ssr,result -> sr - result -> ssr); }printf("\n全体牧师和野⼈全部到达对岸");free(result);}void goon() /*循环操作选择*/{char choice;for(;;){printf("\n是否继续?(Y/N)\n");scanf ("%s" , &choice);choice=toupper(choice);if(choice=='Y')break;if(choice=='N')exit(0);}}int main(){int flag; /* 标记扩展是否成功*/for( ; ; ){initiate();flag = search ();if(flag == 1){recorder();releasemem();showresult();goon();}else{printf("⽆法找到符合条件的解");releasemem();goon();}}system("pause");return 0;}void initiate(){int x;char choice;uend = unopened = (struct SPQ*)malloc(sizeof(spq));if(uend==NULL){printf("\n内存不够!\n");exit(0);}unopenednum=1;openednum=0;unopened -> upnode = unopened; /* 保存⽗结点的地址以成链表*/ unopened -> nextnode = unopened; unopened -> sr = slavenum;unopened -> pr = pristnum;unopened -> sl = 0;unopened -> pl = 0;unopened -> sst = 0;unopened -> spt = 0;unopened -> ssr = 0;unopened -> spr = 0;unopened -> loop = 0;printf("\n请输⼊牧师⼈数");for(;;){scanf("%d",&x);if(x>0){unopened -> pr = x;break;}else printf("\n输⼊值应⼤于0!\n请重新输⼊");}printf("\n请输⼊野⼈⼈数");for(;;){scanf("%d",&x);if(x>0){unopened -> sr = x;break;}else printf("\n输⼊值应⼤于0!\n请重新输⼊");}}int search(){int flag;struct SPQ *ntx; /* 提供将要扩展的结点的指针*/for( ;; ){ntx = unopened; /* 从待扩展链表中提取最前⾯的⼀个*/if(ntx->loop == maxloop)return 0;addtoopened(ntx); /* 将ntx加⼊已扩展链表,并将这个节点从待扩展链表中去掉*/ flag = stretch(ntx); /* 对ntx进⾏扩展,返回-1,0,1 */if(flag == 1)return 1;}}int stretch(struct SPQ *ntx){int fsr , fpr ; /* 在右岸上的⼈数*/int fsl , fpl ; /* 在左岸上的⼈数*/int sst , spt ; /* 出发时在船上的⼈数*/int ssr , spr ; /* 返回时船上的⼈数*/struct SPQ *newnode;for (sst = 0 ; sst <= 2 ; sst++) /* 讨论不同的可能性并判断是否符合条件*/ { fsr = ntx -> sr;fpr = ntx -> pr;fsl = ntx -> sl;fpl = ntx -> pl;if ((sst <= fsr) && (( 2 - sst) <= fpr))/* 满⾜⼈数限制*/{spt = 2 - sst;fsr = fsr - sst;fpr = fpr - spt;if((fpr == 0) && (fsr == 0))/* 搜索成功*/{newnode = (struct SPQ*) malloc (sizeof(spq));if(newnode==NULL){printf("\n内存不够!\n");exit(0);}newnode -> upnode = ntx; /* 保存⽗结点的地址以成链表*/newnode -> nextnode = NULL;newnode -> sr = 0;newnode -> pr = 0;newnode -> sl = opened -> sr;newnode -> pl = opened -> pr;newnode -> spr = 0;newnode -> loop = ntx -> loop + 1;oend -> nextnode = newnode;oend = newnode;openednum++;return 1;}else if ((fpr - fsr) * fpr >= 0) /* 判断是否满⾜传教⼠⼈数必须⼤于或等于野⼈⼈数*/ {fsl = fsl + sst;fpl = fpl + spt;for (ssr = 0 ; ssr <= 1 ; ssr++) /* 返回*/{int ffsl , ffpl;if ((ssr <= fsl) && ((1 - ssr) <= fpl)){spr = 1 - ssr;ffsl = fsl - ssr;ffpl = fpl - spr;if ((ffpl - ffsl) * ffpl >= 0){ /* 若符合条件则分配内存并付值*/int ffsr , ffpr;ffsr = fsr + ssr;ffpr = fpr + spr;newnode = (struct SPQ*) malloc (sizeof(spq));if(newnode==NULL){printf("\n内存不够!\n");exit(0);}newnode -> upnode = ntx; /* 保存⽗结点的地址以成链表*/ newnode -> sr = ffsr; newnode -> pr = ffpr;newnode -> spt = spt;newnode -> ssr = ssr;newnode -> spr = spr;newnode -> loop = ntx -> loop + 1;uend -> nextnode = newnode;uend = newnode;unopenednum++;}}}}}}return 0;}4.程序调试(实验数据记录——根据程序要求输⼊⼏组不同数据,记录程序运⾏结果,并分析结果,分析程序运⾏中出现的主要错误。
青蛙过河实训报告

一、实训背景随着科技的不断发展,编程能力已经成为现代人必备的技能之一。
为了提高自己的编程能力,我参加了青蛙过河实训项目。
青蛙过河是一道经典的算法题,要求我们模拟一只青蛙在河上跳跃的过程,找出青蛙能否成功跳到对岸的方法。
通过这个实训,我不仅加深了对算法的理解,还提升了代码编写的技巧。
二、实训目的1. 理解并掌握青蛙过河问题的算法原理;2. 提高编程能力和逻辑思维能力;3. 学会使用合适的编程语言和数据结构解决实际问题;4. 培养团队合作精神和沟通能力。
三、实训内容1. 问题分析青蛙过河问题可以描述为:有一只青蛙站在河边的位置0,河上有一堆石头,石头编号从1到n。
青蛙每次可以跳k-1、k或k+1步,其中k是上一次跳跃的步数。
现在需要判断青蛙是否能够跳到对岸。
2. 算法设计为了解决这个问题,我们可以采用动态规划的方法。
具体步骤如下:(1)定义一个数组dp[i],表示青蛙能否跳到第i块石头;(2)初始化dp[0]为true,表示青蛙在起点;(3)遍历数组,对于每个位置i,判断是否可以从前一个位置跳到当前位置;(4)如果可以,则将dp[i]设置为true,否则设置为false;(5)最后,判断dp[n]是否为true,如果为true,则表示青蛙能够跳到对岸。
3. 编程实现在实训过程中,我选择了Python作为编程语言,使用列表来实现动态规划数组dp。
具体代码如下:```pythondef canCross(stones):dp = [False] len(stones)dp[0] = Truefor i in range(1, len(stones)):for j in range(i):if abs(stones[i] - stones[j]) <= stones[j] and dp[j]:dp[i] = Truebreakreturn dp[-1]# 测试用例print(canCross([0, 1, 3, 5, 6, 8, 12, 17])) # 输出:True```4. 结果分析通过测试用例,我们可以看到青蛙能够成功跳到对岸。
农夫过河报告(最终版)

农夫过河报告(最终版).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的状态。
农夫过河实验报告——数据结构
数据结构实验报告——实验四农夫过河的求解本实验的目的是进一步理解顺序表和队列的逻辑结构和存储结构,进一步提高使用理论知识指导解决实际问题的能力。
一、【问题描述】一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。
他要把这些东西全部运到北岸。
他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。
如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。
请求出农夫将所有的东西运过河的方案。
二、【数据结构设计】求解这个问题的简单的方法是一步一步进行试探,每一步搜索所有可能的选择,对前一步合适的选择再考虑下一步的各种方案。
要模拟农夫过河问题,首先需要对问题中每个角色的位置进行描述。
一个很方便的办法是用四位二进制数顺序分别表示农夫、狼、白菜和羊的位置。
用0表示农夫或者某东西在河的南岸,1表示在河的北岸。
例如整数5(其二进制表示为0101) 表示农夫和白菜在河的南岸,而狼和羊在北岸。
现在问题变成:从初始状态二进制0000(全部在河的南岸) 出发,寻找一种全部由安全状态构成的状态序列,它以二进制1111(全部到达河的北岸)为最终目标,并且在序列中的每一个状态都可以从前一状态到达。
为避免瞎费功夫,要求在序列中不出现重复的状态。
实现上述求解的搜索过程可以采用两种不同的策略:一种是广度优先(breadth_first) 搜索,另一种是深度优先(depth_first) 搜索。
本书只介绍在广度优先搜索方法中采用的数据结构设计。
广度优先就是在搜索过程中总是首先搜索下面一步的所有可能状态,再进一步考虑更后面的各种情况。
要实现广度优先搜索,可以使用队列。
把下一步所有可能的状态都列举出来,放在队列中,再顺序取出来分别进行处理,处理过程中把再下一步的状态放在队列里……。
由于队列的操作遵循先进先出的原则,在这个处理过程中,只有在前一步的所有情况都处理完后,才能开始后面一步各情况的处理。
农夫过河 实验报告
农夫过河实验报告
实验报告:农夫过河
实验目的:
1. 了解农夫过河问题的规则和约束条件;
2. 分析农夫过河问题的求解思路;
3. 实现农夫过河问题的求解算法。
实验原理:
农夫过河问题是一种经典的逻辑推理问题,涉及农夫、狼、羊和菜四个角色过河的情景。
根据约束条件,农夫每次只能带一种物品过河,而且农夫不能将狼和羊、羊和菜同时留在岸边,否则会发生危险。
实验步骤:
1. 设计数据结构表示问题的状态,如使用二进制位表示农夫、狼、羊和菜的位置;
2. 使用递归算法实现问题的解法,通过深度优先搜索遍历所有可能的状态,并根据约束条件进行剪枝;
3. 运行程序,输出农夫过河的解答序列。
实验结果:
根据实验步骤中的算法和程序设计,成功地求解了农夫过河问题,并输出了正确的解答序列。
实验结果表明,农夫可以经过
一系列合法的操作,将狼、羊和菜都安全地带过河。
实验结论:
通过本次实验,我们深入理解了农夫过河问题的规则和约束条件,并成功地实现了问题的求解算法。
实验结果表明,农夫过河问题有多种可能的解法,但只有符合约束条件的解才是正确的解答。
这个经典的逻辑推理问题在计算机科学中具有重要的意义,可以用于教学和娱乐等领域。
轮船渡河物理实验报告
一、实验目的1. 理解轮船渡河的基本原理,掌握浮力、动量守恒等物理概念在轮船渡河中的应用。
2. 通过实验验证轮船渡河过程中浮力、动量守恒等物理定律的正确性。
3. 提高对物理现象的观察、分析、解决问题的能力。
二、实验原理轮船渡河过程中,轮船受到的浮力等于其重力,即F浮 = G。
根据阿基米德原理,轮船排开水的体积等于轮船的体积,即V排 = V船。
轮船在水平方向受到的合外力为零,即动量守恒。
三、实验器材1. 轮船模型2. 测量轮船重力的天平3. 测量轮船体积的量筒4. 测量轮船速度的计时器5. 水桶(用于模拟河流)6. 水位计(用于测量水位)7. 记录本和笔四、实验步骤1. 测量轮船的重力G,并记录。
2. 将轮船放入水桶中,测量轮船的体积V船,并记录。
3. 测量水桶中水位的高度h1,并记录。
4. 将轮船从水桶中取出,记录轮船在水平方向的速度v0。
5. 将轮船放入水桶中,测量水桶中水位的高度h2,并记录。
6. 记录轮船渡河过程中的时间t。
7. 计算轮船在水平方向上的加速度a = (v - v0) / t。
8. 根据阿基米德原理,计算轮船受到的浮力F浮= G = ρ水V排g,其中ρ水为水的密度,g为重力加速度。
9. 分析实验数据,验证浮力、动量守恒等物理定律的正确性。
五、实验数据1. 轮船重力G = 100N2. 轮船体积V船= 0.05m³3. 水桶中水位高度h1 = 0.5m4. 轮船水平方向速度v0 = 0.5m/s5. 水桶中水位高度h2 = 0.7m6. 轮船渡河时间t = 10s7. 轮船水平方向加速度a = 0.05m/s²8. 水的密度ρ水= 1000kg/m³9. 重力加速度g = 9.8m/s²六、实验结果与分析1. 根据阿基米德原理,轮船受到的浮力F浮 = G = 100N。
2. 轮船在水平方向上的加速度a = 0.05m/s²,说明轮船在渡河过程中受到的合外力为零,符合动量守恒定律。
C++实现传教士与野人过河问题实验报告
else operation.push_back(" 0
2 | 右岸->左岸");
currentState.churchL = lastcurrentState.churchL;
currentState.wildL = lastcurrentState.wildL - 2 * lastcurrentState.boat;
currentState.boat = -lastcurrentState.boat;
lastParameters.push_back(currentState);
CvsWdfs(currentState, lastParameters,operation, 0);
operation.pop_back();
lastParameters.pop_back(); return 0; }
int main(){ int churchL = 3, wildL = 3, churchR = 0, wildR = 0;//分别用来计算左岸和右岸的传教士
和野人 vector <riverSides> lastParameters;//保存每一步移动操作的两岸传教士、野人人数 vector <string> operation;//保存当前操作的描述
if (lastcurrentState.boat == lastParameters[i].boat) return 0;
} } //检验人数数据合法性 if (lastcurrentState.churchL < 0 || lastcurrentState.wildL < 0 || lastcurrentState.churchR < 0 || lastcurrentState.wildR < 0)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
if(a[i][3]==0) printf("farmer ");
if(a[i][0]&&a[i][1]&&a[i][2]&&a[i][3]) printf("none");
printf("
");
printf("west: ");
if(a[i][0]==1) printf("wolf ");
if(a[i][1]==1) printf("goat ");
if (i == -1) { search(Step + 1); }
else if (a[Step][i] == a[Step][3]) {
a[Step + 1][i] = a[Step + 1][3]; search(Step + 1); } } 每次循环从-1 到 2 依次代表农夫渡河时为一人、带狼、带羊、带白菜通过, 利用语句 “b[Step] = i”分别记录每一步中农夫的渡河方式,“a[Step + 1][i] = a[Step + 1][3]”即利用赋值方式使该项与农夫一同到对岸或者回到本岸。若 渡河成功,则依次输出渡河方式。 “i <= 2”即递归操作的界限,当若 i=2 时 仍无符合条件的方式,则渡河失败。
east east east
east east
: farmer goat wolf cabbage west : none
The 1 time
: wolf cabbage
west : farmer goat
------ farmer
: farmer wolf cabbage
west : goat
The 2 time
六、调试过程中的问题
(1)递归循环中,开始时编写 for (i = 0; i <= 3; i++),但当下面写到 a[Step][i] 时发现若 i 从 0 开始则二维数组中每一步都需定义为 a[Step][i-1],给写程序 造成很多不便,同时造成定义混乱,因此修改后将 for 循环定义为 for (i = -1; i <= 2; i++)。 (2)开始运行程序之后,发现程序无法正常运行,开始无显示,经过调试之后 显示乱码,最终发现程序无法正常终止,因为虽然定义了 i 的上限,但并没有定
------ farmer and wolf
: cabbage
west : farmer goat wolf
------ farmer and goat
: farmer goat cabbage
west : wolf
……
east : none
west : farmer goat wolf cabbage
0
0
0
0
成功渡河之后,二维数组存储应为
a[step][0] a[step][1] a[step][2] a[step][3]
1
1
1
1
则有 a[Step][0] + a[Step][1] + a[Step][2] + a[Step][3] == 4。
题目要求狼和羊、羊和白菜不能在一起,即若有下述情况
printf("%s\n",name[b[i] + 1]);
}
}
}
printf("\n\n\n\n");
return;
}
for (i = 0; i < Step; i++)
{
if (memcmp(a[i], a[Step], 16) == 0)//若该步与以前步骤相同,取消操作 { return; } } if (a[Step][1] != a[Step][3] && (a[Step][2] == a[Step][1] || a[Step][0] == a[Step][1])) //若羊和农夫不在一块而狼和羊或者羊和 //白菜在一块,则取消操作 { return; } for (i = -1; i <= 2; i++)//递归,从带第一种开始一次向下循环;同时限定 递归界
0—wolf 1—goat 2—cabbage 3—farmer
将东岸和西岸数字化,,其对应为:
0—东岸
1—西岸
具体对应实例比如在第 3 步之后狼在东岸,羊在西岸,白菜在东岸,农夫在西岸,
则其存储结果为:
a[3][0] a[3][1] a[3][2] a[3][3]
0
1
0
1
故,最初存储状态为
a[0][0] a[0][1] a[0][2] a[0][3]
为 1,输出结果,进入回归步骤
{ for (i = 0; i <=Step; i++)
//能够依次输出不同的方案
{
printf("east: ");
if(a[i][0]==0) printf("wolf ");
if(a[i][1]==0) printf("goat ");
if(a[i][2]==0) printf("cabbage ");
printf("
the %d time\n",i+1);
if(i>0&&i<Step)
{ if (a[i][3] == 0)//农夫在本岸
{
printf("
-----> farmer ");
printf("%s\n",name[b[i] + 1]);
} else//农夫在对岸
{
printf("
<----- farmer ");
在递归的过程中没进行一步都需要判断条件决定是否继续进行此次操作,具 体的判断代码为: (1)if (a[Step][0] + a[Step][1] + a[Step][2] + a[Step][3] == 4)
{…… return} 若该种步骤能使各值均为 1,渡河成功,输出结果,进入回归步骤。 (2)if (memcmp(a[i], a[Step], 16) == 0) { return;} 若该步与以前步骤相同,返回操作。 ( 3 ) if (a[Step][1] != a[Step][3] && (a[Step][2] == a[Step][1] || a[Step][0] == a[Step][1])) {return;} 若羊和农夫不在一块而狼和羊或者羊和白菜在一块,则返回操作。
if(a[i][2]==1) printf("cabbage ");
if(a[i][3]==1) printf("farmer ");
if(!(a[i][0]||a[i][1]||a[i][2]||a[i][3])) printf("none");
printf("\n\n\n");
if(i<Step)
七、课程设计总结
(1)若代码所要实现的功能较多或者程序较为复杂,可先设计好程序的整体框 架,画出流程图,然后依次编写代码分别实现上述功能,最后将各部分代码按照 顺序结合起来,对各个参数稍加调试,便可得到清晰正确的程序。 (2)在用到循环或者递归等算法时,很容易出现对某一界限界定不明导致程序 无法正常运行,而且这些疏漏之处往往是简短几步中不容易发现的,这就需要细 心、耐心地梳理清楚各条脉络,找出问题所在。 (3)在编写程序时,应在方便的情况下尽可能使用同一种变量进行各步的运算, 减少不必要的变量定义,以免造成代码过于混乱。 (4)复杂代码以及大型程序需要小组所有成员共同努力,既可以对同一个问题 进行讨论,找出最简便的实现方式,也可以每个人负责不同的部分,在所有人的 努力下共同创造出一份完整的代码,让它顺利地运行。
a[Step][1] != a[Step][3] && (a[Step][2] == a[Step][1] || a[Step][0] ==
a[Step][1])
则出现错误,应返回操作。
程序采用递归算法,主程序结构的设计为
开始
a[0][0]=0 … … a[0][3]=0
递归
结束
同时定义一维数组 b[N]来存储每一步中农夫是如何过河的。设计程序中实 现递归操作部分的核心代码为 for (i = -1; i <= 2; i++) { b[Step] = i; memcpy(a[Step + 1], a[Step], 16); a[Step + 1][3] = 1 - a[Step + 1][3];
#define N 15
int a[N][4];
int b[N];
char *name[] =
{
"
",
"and wolf",
"and goat",
"and cabbage"
};
void search(int Step)
{
int i; if (a[Step][0] + a[Step][1] + a[Step][2] + a[Step][3] == 4)//若该种步骤能使各值均
int main()
{ printf("\n\n search(0); return 0; }
农夫过河问题,解决方案如下:\n\n\n");