数据结构课程设计报告(农夫过河)

合集下载

农夫过河

农夫过河

农夫过河问题——程序设计(2009-06-05 13:38:22)标签:分类:一、问题需求分析一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。

他要把这些东西全部运到北岸。

问题是他面前只有一条小船,船小到只能容下他和一件物品,另外只有农夫能撑船。

另外,因为狼能吃羊,而羊爱吃白菜,所以农夫不能留下羊和白菜或者狼和羊单独在河的一边,自己离开。

请问农夫该采取什么方案才能将所有的东西运过河呢?二、算法选择求解这个问题的最简单的方法是一步一步进行试探,每一步都搜索所有可能的选择,对前一步合适的选择再考虑下一步的各种方案。

用计算机实现上述求解的搜索过程可以采用两种不同的策略:一种是广度优先(breadth_first) 搜索,另一种是深度优先(depth_first) 。

广度优先:u 广度优先的含义就是在搜索过程中总是首先搜索下面一步的所有可能状态,然后再进一步考虑更后面的各种情况。

u 要实现广度优先搜索,一般都采用队列作为辅助结构。

把下一步所有可能达到的状态都列举出来,放在这个队列中,然后顺序取出来分别进行处理,处理过程中把再下一步的状态放在队列里……。

u 由于队列的操作遵循先进先出的原则,在这个处理过程中,只有在前一步的所有情况都处理完后,才能开始后面一步各情况的处理。

三、算法的精化要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。

一个很方便的办法是用四位二进制数顺序分别表示农夫、狼、白菜和羊的位置。

例如用0表示农夫或者某东西在河的南岸,1表示在河的北岸。

因此整数5(其二进制表示为0101) 表示农夫和白菜在河的南岸,而狼和羊在北岸。

四、算法的实现完成了上面的准备工作,现在的问题变成:从初始状态二进制0000(全部在河的南岸) 出发,寻找一种全部由安全状态构成的状态序列,它以二进制1111(全部到达河的北岸) 为最终目标,并且在序列中的每一个状态都可以从前一状态通过农夫(可以带一样东西)划船过河的动作到达。

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

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

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

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

农夫怎么才能把所有的东西安全运过河呢?实验要求如下:(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;}实验结果:四、实验总结。

农夫过河问题(数据结构课设)

农夫过河问题(数据结构课设)

#include "stdafx.h"#include <stdio.h>/*0代表在河的这边;1代表在河的对岸*/struct Condition {int farmer;int wolf;int sheep;int cabbage;};/*设置结构体*/struct Condition conditions [100];/*结构体条件数组*/char* action[100];/*字符串数组*/ void takeWolfOver(int i)/*把狼带过去*/ {action[i] = "带狼过去. (wolf)--->对岸";conditions[i+1].wolf=1;conditions[i+1].sheep=conditions[i].sheep;conditions[i+1].cabbage=conditions[i].cabbage;} void takeWolfBack(int i)/*把狼带回来*/{action[i] = "带狼回来. 本岸<---(wolf)";conditions[i+1].wolf=0;conditions[i+1].sheep=conditions[i].sheep;conditions[i+1].cabbage=conditions[i].cabbage;} void takeSheepOver(int i)/*把羊带过去*/{action[i] = "带羊过去. (sheep)--->对岸";conditions[i+1].wolf=conditions[i].wolf;conditions[i+1].sheep=1;conditions[i+1].cabbage=conditions[i].cabbage;} void takeSheepBack(int i)/*把羊带回来*/{action[i] = "带羊回来. 本岸<---(sheep)";conditions[i+1].wolf=conditions[i].wolf;conditions[i+1].sheep=0;conditions[i+1].cabbage=conditions[i].cabbage;} void takeCabbageOver(int i)/*把菜带过去*/{action[i] = "带菜过去. (cabbage)--->对岸";conditions[i+1].wolf=conditions[i].wolf;conditions[i+1].sheep=conditions[i].sheep;conditions[i+1].cabbage=1;} void takeCabbageBack(int i)/*把菜带回来*/{action[i] = "带菜回来. 本岸<---(cabbage)";conditions[i+1].wolf=conditions[i].wolf;conditions[i+1].sheep=conditions[i].sheep;conditions[i+1].cabbage=0;} void getOverBarely(int i)/*过河时的情况*/{action[i] = "空手过去. (barely)--->对岸";conditions[i+1].wolf=conditions[i].wolf;conditions[i+1].sheep=conditions[i].sheep;conditions[i+1].cabbage=conditions[i].cabbage;/*全不动*/} void getBackBarely(int i)/*返回时的情况*/{action[i] = "空手回来. 本岸<---(barely)";conditions[i+1].wolf=conditions[i].wolf;conditions[i+1].sheep=conditions[i].sheep;conditions[i+1].cabbage=conditions[i].cabbage;} void showSolution(int i)/*显示解决方法*/{int c;printf("\n");printf ("%s\n", "解决办法:");for(c=0; c<i; c++){printf ("step%d: %s\n", c+1, action[c]);/*换行输出*/}printf ("%s\n", "Successful!");}void tryOneStep(int i)/*再试一遍*/{int c;int j;if(i>=100)/*检查循环是否出现问题*/{printf("%s\n", "渡河步骤达到100步,出错!");return;}if(conditions[i].farmer==1&&conditions[i].wolf==1&&conditions[i].sheep==1&&conditions[i].cabbage==1)/*检查是否都过河*/{showSolution(i);/*是的,都过河了.返回*/return;}if((conditions[i].farmer!=conditions[i].wolf &&conditions[i].wolf==conditions[i].sheep)||(conditions[i].farmer!=conditions[i].sheep && conditions[i].sheep==conditions[i].cabbage))/*检查是否丢失,出错*/{/*不,狼会吃掉羊,或者羊会吃掉菜的*/return;}/*检查条件是否满足*/for (c=0; c<i; c++){if(conditions[c].farmer==conditions[i].farmer&&conditions[c].wolf==conditions[i].wolf&&conditions[c].sheep==conditions[i].sheep&&conditions[c].cabbage==conditions[i].cabbage) {return;}}j=i+1;if(conditions[i].farmer==0)/*农夫在河这边*/{conditions[j].farmer=1;getOverBarely(i);tryOneStep(j);if(conditions[i].wolf==0)/*如果狼没带过去*/{takeWolfOver(i);tryOneStep(j);}if(conditions[i].sheep==0){takeSheepOver(i);tryOneStep(j);}if(conditions[i].cabbage==0){takeCabbageOver(i);tryOneStep(j);}}else{conditions[j].farmer=0;getBackBarely(i);tryOneStep(j);if(conditions[i].wolf==1){takeWolfBack(i);tryOneStep(j);}if(conditions[i].sheep==1){takeSheepBack(i);tryOneStep(j);}if(conditions[i].cabbage==1){takeCabbageBack(i);tryOneStep(j);}}} int main()/*主函数*/{printf("问题:农夫过河。

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

农夫过河问题(C++编写)
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)、如果上两个条件都不满,则可执行运输的动作,但每次都应考虑,该运 输情况以前是否执行过(即两岸以及船上的东西以及各自位置和以前完全相同),

农夫过河问题

农夫过河问题

课程设计题目:农夫过河一.问题描述一个农夫带着一只狼、一只羊和一箩白菜,身处河的南岸。

他要把这些东西全部运到北岸。

他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。

过河有以下规则:(1)农夫一次最多能带一样东西(或者是狼、或者是羊、或者是白菜)过河;(2)当农夫不在场是狼会吃羊;(3)当农夫不在场是羊会吃掉白菜。

现在要求为农夫想一个方案,能将3样东西顺利地带过河。

从出事状态开始,农夫将羊带过河,然后农夫将羊待会来也是符合规则的,然后农夫将羊带过河仍然是符合规则的,但是如此这般往返,搜索过程便进入了死循环,因此,在这里,采用改进的搜索算法进行搜索。

二.基本要求(1)为农夫过河问题抽象数据类型,体会数据模型在问题求解中的重要性;(2)要求利用数据结构的方法以及C++的编程思想来完成问题的综合设计;(3)在问题的设计中,使用深度优先遍历搜索方式,避免死循环状态;(4)设计一个算法求解农夫过河问题,并输出过河方案;(5)分析算法的时间复杂度。

三.概要设计(1)数据结构的设计typedef struct // 图的顶点{int farmer; // 农夫int wolf; // 狼int sheep; // 羊int veget; // 白菜}Vertex;设计Vertex结构体的目的是为了存储农夫、狼、羊、白菜的信息,因为在遍历图的时候,他们的位置信息会发生变化,例如1111说明他们都在河的北岸,而0000说明他们都在河的南岸。

t ypedef struct{int vertexNum; // 图的当前顶点数Vertex vertex[VertexNum]; // 顶点向量(代表顶点)bool Edge[VertexNum][VertexNum]; // 邻接矩阵. 用于存储图中的边,其矩阵元素个数取决于顶点个数,与边数无关}AdjGraph; // 定义图的邻接矩阵存储结构存储图的方法是用邻接矩阵,所以设计一个简单的AdjGraph结构体是为了储图的顶点数与边数,农夫过河问题我采用的是图的深度优先遍历思想。

农夫过河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)设计队列的存储结构并实现队列的基本操作(建立空队列、判空、入队、出队、取对头元素),也可以使用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;}实验结果:四、实验总结。

数据结构农夫过河项目课报告

数据结构农夫过河项目课报告

数据结构农夫过河项目课报告数据结构-农夫过河项目课报告-计算机四班第七组项目名称:农夫过河算法与数据结构设计专业班级:计算机科学与技术四班学生姓名:王喆指导教师: 完成日期:2015年12月28日数据结构-农夫过河项目课报告-计算机四班第七组农夫过河算法与数据结构设计摘要农夫过河问题即一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸,他需要把这些东西全部运到河的北岸。

而他只有一条小船,且这只小船小到只能容下他和一件物品,另外只有农夫能撑船。

农夫不能留下狼和羊自己离开,也不能留下白菜和羊自己离开,更不能留下狼,羊和白菜而独自离开,因为没有农夫的照看,狼就要吃掉羊,而羊又要吃掉白菜。

好在狼是是肉动物,它不吃白菜,问农夫应该采取什么方案才能将所有的东西安全地从河的南岸运到北岸,这类农夫问题是一个传统的数据结构问题,农夫过河问题根据图求解的搜索过程可采用两种不同的策略:一种是图的深度优先遍历搜索,另外一种是广度优先遍历搜索。

如果采用深度优先遍历搜索,则需要采用递归的方式来编写程序,而这种程序的系统的开销比较大,如果采用广度优先搜索,则可以借助队列的方式,这种方式开销较小。

关键字:农夫过河,广度优先遍历搜索,队列,深度优先遍历搜索,递归。

2数据结构-农夫过河项目课报告-计算机四班第七组目录1.前言…………………………………………………………42.设计任务与技术要求………………………………………43.总体设计方案………………………………………………44.数据结构和算法的设计……………………………………55.程序测试与调试(一)……………………………………7 6.程序测试与调试(二)..........................................9 7.程序出现的问题及修改情况....................................14 8.心得与体会.........................................................14 参考文献 (15)3数据结构-农夫过河项目课报告-计算机四班第七组1.前言课程研究项目是《数据结构》课程学习的重要方式之一,也是《数据结构》课程学习的重要组成部分之一。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录引言 (2)1 问题描述 (3)基本要求 (3)2.1为农夫过河问题抽象数据模型体会数据模型在问题求解中的重要性; (3)2.2设计一个算法求解农夫过河问题,并输出过河方案; (3)3 概要设计 (3)3.1数据结构的设计。

(3)3.1.1农夫过河问题的模型化 (3)3.1.2 算法的设计 (4)4、运行与测试 (6)5、总结与心得 (7)附录 (7)参考文献 (13)引言所谓农夫过河问题是指农夫带一只狼、一只羊和一棵白菜在河南岸, 需要安全运到北岸。

一条小船只能容下他和一件物品, 只有农夫能撑船。

问农夫怎么能安全过河, 当然狼吃羊, 羊吃白菜, 农夫不能将这两种或三种物品单独放在河的一侧, 因为没有农夫的照看, 狼就要吃羊, 而羊可能要吃白菜? 这类问题的实质是系统的状态问题, 要寻求的是从初始状态经一系列的安全状态到达系统的终止状态的一条路径。

1 问题描述一个农夫带一只狼、一棵白菜和一只羊要从一条河的南岸过到北岸,农夫每次只能带一样东西过河,但是任意时刻如果农夫不在场时,狼要吃羊、羊要吃白菜,请为农夫设计过河方案。

基本要求2.1为农夫过河问题抽象数据模型体会数据模型在问题求解中的重要性;2.2设计一个算法求解农夫过河问题,并输出过河方案;3 概要设计3.1 数据结构的设计。

3.1.1农夫过河问题的模型化分析这类问题会发现以下特征:有一组状态( 如农夫和羊在南, 狼和白菜在北) ; 从一个状态可合法地转到另外几个状态( 如农夫自己过河或农夫带着羊过河) ; 有些状态不安全( 如农夫在北, 其他东西在南) ; 有一个初始状态( 都在南) ; 结束状态集( 这里只有一个, 都在北) 。

问题表示: 需要表示问题中的状态, 农夫等位于南P北( 每个有两种可能) 。

可以采用位向量, 4 个二进制位的0P1 情况表示状态, 显而易见, 共24= 16种可能状态。

从高位到低位分别表示农夫、狼、白菜和羊。

0000( 整数0) 表示都在南岸, 目标状态1111( 即整数15) 表示都到了北岸。

有些状态0011,0101, 0111, 0001, 1100, 1001 是不允许出现的, 因为这些状态是不安全状态。

根据上述条件可以画出系统的状态图如图1 所示。

图1 系统状态转换图其中双向的箭头表示状态可逆, 即农夫可以带着某种东西过去, 也可以带着该东西回来。

箭头上的字母表示农夫所携带的东西:f( farmer) , w(wolf) , g(goat) , c( cabbage) 分别表示农夫自己、农夫携带狼、农夫携带羊、农夫携带菜过河。

现在的问题转化为: 找一条合法路径( 相邻状态之间的转移合法) , 从开始状态到某个结束状态, 途中不经过不安全状态。

3.1.2 算法的设计求农夫、狼、白菜和羊的当前状态的函数为每一种状态做测试, 状态安全则返回0, 否则返回1。

安全性判断函数, 若状态安全则返回0int farmer(int location) //判断农夫位置对0做与运算,还是原来的数字,用来判断位置{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) // 若状态安全则返回 true{if ((goat(location) == cabbage(location)) && (goat(location) !=farmer(location)) )return 0;if ((goat(location) == wolf(location)) && (goat(location) !=farmer(location)))return 0;return 1; //其他状态是安全的借助于位向量和按位运算符, 很容易描述过河动作, 这种问题表示的设计使得程序的实现比较容易。

算法的基本思想: 利用队列moveTo 记录可到的尚未向前探试的状态, 数组元素route [ i] 记录状态i的路径[ 前一状态] , - 1 表示尚未访问。

则算法的高级抽象可描速为:{初始状态出发点入队列;所有其他点状态标记为未访问;while ( ! isEmptyQueue seq ( moveTo) &&( route[ 15] == - 1) ){从moveTo 取出一个状态;试探所有由这个状态出发可能到达的状态;if( 能到达的状态安全且未访问过){记录到它的路径;压入队列;}}}精化上速算法得到问题的具体算法如下:void farmerProblem( ){int movers, i, location, newlocation;int route[16]; //记录已考虑的状态路径int print[MAXNUM];PSeqQueue moveTo;moveTo = createEmptyQueue_seq( );//新的队列判断路径enQueue_seq(moveTo, 0x00); //初始状态为0for (i = 0; i < 16; i++)route[i] = -1; //-1表示没有记录过路径route[0]=0;while (!isEmptyQueue_seq(moveTo)&&(route[15]== -1))//队列不为空,路径未满时循环{location = frontQueue_seq(moveTo); //从队头出队,location表示位置,0为北岸,1为南岸deQueue_seq(moveTo);//已出队的删除for (movers = 1; movers <= 8; movers<<= 1) //向左移位,movers分别0001,0010,0100,1000,也就是依次判断过河的可行性{if ((0 != (location & 0x08)) == (0 != (location & movers)))//判断农夫和要移动的物品是否在同岸{newlocation = location^(0x08|movers);//过岸if (safe(newlocation) && (route[newlocation] == -1))//判断是否安全,以及路径是否可用{route[newlocation] = location;enQueue_seq(moveTo, newlocation);//记录路径并入队,位置改变4、运行与测试5、总结与心得“纸上得来终觉浅,绝知此事要躬行。

”通过这两周的课程设计,使我对书上的的理论知识有了更深的理解,也使我对于团队合作有了新的认识,意识到团队的力量。

课程设计是一个必须经历的过程,是我们理解书本知识、熟悉所学专业的一次很好实践。

在这次设计过程中,体现出自己单独设计程序的能力以及综合运用知识的能力,体会了学以致用、突出自己劳动成果的喜悦心情,从中发现自己平时学习的不足和薄弱环节,从而加以弥补。

附录#include<iostream.h>#include<stdio.h>#define MAXNUM 20typedef struct //顺序队列类型定义{int f, r; //f表示头,r 表示尾int q[MAXNUM];//顺序队}SeqQueue ,*PSeqQueue;PSeqQueue createEmptyQueue_seq( ) //创建队列{PSeqQueue paqu = new SeqQueue;if (paqu == NULL)cout<<"Out of space!"<<endl;elsepaqu->f=paqu->r=0;return (paqu);}int isEmptyQueue_seq( PSeqQueue paqu ) //判断 paqu 所指是否是空队列{return paqu->f==paqu->r;}void enQueue_seq(PSeqQueue paqu,int x) //在队列中插入一元素 x{if ((paqu->r+1)%MAXNUM==paqu->f)cout<<"队列已满."<<endl;else{paqu->q[paqu->r]=x;paqu->r=(paqu->r+1)%MAXNUM;}}void deQueue_seq(PSeqQueue paqu) //删除队列头部元素{if( paqu->f==paqu->r)cout<<"队列为空"<<endl;elsepaqu->f=(paqu->f+1)%MAXNUM;}int frontQueue_seq( PSeqQueue paqu ) //对非空队列,求队列头部元素{return (paqu->q[paqu->f]);}int farmer(int location) //判断农夫位置对0做与运算,还是原来的数字,用来判断位置{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) // 若状态安全则返回 true{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 farmerProblem( ){int movers, i, location, newlocation;int route[16]; //记录已考虑的状态路径int print[MAXNUM];PSeqQueue moveTo;moveTo = createEmptyQueue_seq( );//新的队列判断路径enQueue_seq(moveTo, 0x00); //初始状态为0for (i = 0; i < 16; i++)route[i] = -1; //-1表示没有记录过路径route[0]=0;while (!isEmptyQueue_seq(moveTo)&&(route[15]== -1))//队列不为空,路径未满时循环{location = frontQueue_seq(moveTo); //从队头出队,location表示位置,0为北岸,1为南岸deQueue_seq(moveTo);//已出队的删除for (movers = 1; movers <= 8; movers<<= 1) //向左移位,movers分别0001,0010,0100,1000,也就是依次判断过河的可行性{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){cout<<"过河步骤是 : "<<endl;i=0;for(location = 15; location >= 0; location = route[location]){print[i]=location;i++;if (location == 0)break;}int num=i-1;int temp[20][4];int j;for(i=num;i>=0;i--){for(j=3;j>=0;j--){temp[num-i][j]=print[i]%2;print[i]/=2;temp[0][j]=0;temp[num+1][j]=1;}}/* for(i=0;i<=num;i++){for(j=0;j<4;j++)cout<<temp[i][j]<<" ";cout<<endl;}*/for(i=1;i<=num;i++){cout<<"\t\t\tNO . "<<i<<"\t";if(i%2==1){if(temp[i][3]!=temp[i-1][3])cout<<"农夫带羊过南岸";if(temp[i][2]!=temp[i-1][2])cout<<"农夫带白菜过南岸";if(temp[i][1]!=temp[i-1][1])cout<<"农夫带狼过南岸";if(temp[i][3]==temp[i-1][3]&&temp[i][2]==temp[i-1][2]&&temp[i][1]==temp[i-1 ][1])cout<<"农夫自己过南岸";}else if(i%2==0){if(temp[i][3]!=temp[i-1][3])cout<<"农夫带羊回北岸";if(temp[i][2]!=temp[i-1][2])cout<<"农夫带白菜回北岸";if(temp[i][1]!=temp[i-1][1])cout<<"农夫带狼回北岸";if(temp[i][3]==temp[i-1][3]&&temp[i][2]==temp[i-1][2]&&temp[i][1]==temp[i-1 ][1])cout<<"农夫自己回北岸";}cout<<endl;}}elsecout<<"No solution."<<endl;}int main() /*主函数*/{farmerProblem();return 0;}参考文献1.王红梅、王涛、胡明编著。

相关文档
最新文档