农夫过河问题

合集下载

实习六-农夫过河问题

实习六-农夫过河问题

农夫过河问题一、需求分析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++编写)

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

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

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

cout<<" **
------------------------
**\n";
cout<<" **
|
农夫过河问题
|
**\n";
cout<<" **
------------------------
**\n";
cout<<"
****************************************************************************\n";
1、问题描述
从前,一个农夫带着一只狼,一只羊和一棵白菜要河(注意该狼被农夫训服了,但还会 吃羊)。他要将所有东西安全的带到河的对岸,不幸的是河边只有一条船,只能装下农夫和 他的一样东西,并且农夫必须每次都随船过,因为只有他能撑船。在无人看管的情况下,狼 要吃羊,羊要吃白菜,因此,农夫不能在河的某边岸上单独留下狼和羊,也不能单独留下羊 和白菜。那么农夫如何才能使三样东西平安过河呢?
3)、如果上两个条件都不满,则可执行运输的动作,但每次都应考虑,该运 输情况以前是否执行过(即两岸以及船上的东西以时四者各自的状态,并递归的进行下一次运载。
5、系统测试
6、经验总结
解决实际问题时,应先分析实际问题,找出实际问题的所有约束条件, 然后对问题进行数学模型的抽象化,抓主要因素,省去一些不需要的因素,将其 抽象为数学问题,然后再从整体上设计算法,搭建程序的框架,最后一步步完善 细节,这样做,会使本来毫无头绪的问题变得清晰起来。
if (a[ferryTimes][i] == a[ferryTimes][3]) {

题目 流程农夫过河

题目 流程农夫过河

题目流程农夫过河一、基础过河规则类题目(1 - 5题)题目1:农夫带着狼、羊和一筐白菜要过河。

只有一条小船,农夫每次只能带一样东西过河。

如果农夫不在,狼会吃羊,羊会吃白菜。

请问农夫怎样才能安全地把狼、羊和白菜都运到河对岸?解析:1. 农夫先把羊运到河对岸,然后农夫独自返回。

- 原因是狼不吃白菜,这样河这边留下狼和白菜是安全的。

2. 农夫再把狼运到河对岸,然后农夫带着羊返回。

- 因为如果不把羊带回来,狼会吃羊。

3. 农夫把白菜运到河对岸,然后农夫独自返回。

- 此时河对岸有狼和白菜,是安全的。

4. 最后农夫把羊运到河对岸。

题目2:农夫要带狐狸、鸡和一袋米过河。

船很小,农夫每次只能带一个东西过河。

如果农夫不在,狐狸会吃鸡,鸡会吃米。

农夫应该怎样安排过河顺序?解析:1. 农夫先把鸡运到河对岸,然后农夫独自返回。

- 这样河这边留下狐狸和米是安全的。

2. 农夫再把狐狸运到河对岸,然后农夫带着鸡返回。

- 防止狐狸吃鸡。

3. 农夫把米运到河对岸,然后农夫独自返回。

- 此时河对岸有狐狸和米,安全。

4. 最后农夫把鸡运到河对岸。

题目3:农夫带着狗、兔子和一篮胡萝卜过河。

船只能载农夫和一样东西。

若农夫不在,狗会咬兔子,兔子会吃胡萝卜。

怎样安全过河?解析:1. 农夫先带兔子过河,然后独自返回。

- 因为狗不吃胡萝卜,这样河这边狗和胡萝卜是安全的。

2. 农夫再带狗过河,然后带兔子返回。

- 避免狗咬兔子。

3. 农夫带胡萝卜过河,然后独自返回。

- 此时河对岸狗和胡萝卜安全。

4. 最后农夫带兔子过河。

题目4:有个农夫要带蛇、鼠和一袋谷子过河,船每次只能载农夫和一样东西。

农夫不在时,蛇会吃鼠,鼠会吃谷子。

如何安全渡河?解析:1. 农夫先带鼠过河,然后独自返回。

- 此时河这边蛇和谷子是安全的。

2. 农夫再带蛇过河,然后带鼠返回。

- 防止蛇吃鼠。

3. 农夫带谷子过河,然后独自返回。

- 河对岸蛇和谷子安全。

4. 最后农夫带鼠过河。

题目5:农夫带着猫、鱼和一盆花过河。

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

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

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

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

农夫怎么才能把所有的东西安全运过河呢?实验要求如下:(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)我们在学习时也常常有这样的问题,面对某个复杂的问题,总是从多角度考虑它,然后得出最佳的解决方案。

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

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

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

宽搜农夫过河问题

宽搜农夫过河问题

农夫过河问题宽搜(bfs)算法详解农夫过河问题(农夫、狼、羊和白菜的问题),描述如下:一个农夫,带着一只狼、一只羊、和一棵白菜,身处河的南岸,他要把这些东西全部运到北岸。

农夫的面前有一条小船,船小到只能容下他和一件物件。

另外,只能农夫会撑船。

又因为狼能吃羊,而羊爱吃白菜,所以农夫不能留下羊和白菜而自己离开,也不能留下狼和羊而自己离开。

但狼属于食肉动物,不吃白菜。

问农夫采取什么方案才能将所有的东西运过河?解题思路农夫过河问题的求解方法是使用广度优先搜索(BFS),即在搜索过程中总是最先搜索下面一步的所有可能状态,然后再进行考虑更后面的各种情况。

要实现广度优先搜索,一般采用队列结构。

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

在采用编程解决农夫过河的问题时,首先需要考虑以下几个问题:•程序中为了方便描述农夫过河过程中几个角色的位置(位于南岸还是北岸),最好的方法是用4 个二进制数,分别顺序表示农夫、狼、白菜和羊的位置。

在本节程序中,用二进制0 表示某角色在河的南岸,用 1 表示某角色在河的北岸。

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

•为了方便获取各个角色当前所在的位置,程序中设置了如下 4 个函数。

其中,函数返回值为1,反之则表示角色在河的北岸://表示农夫状态的函数,返回0 ,表示农夫在南岸,反之在北岸。

int farmer(int location){return(0!=(location & 0x08));}//表示狼的状态的函数,返回0 ,表示农夫在南岸,反之在北岸int wolf(int location){return(0!=(location & 0x04));}//表示白菜状态的函数,返回0 ,表示农夫在南岸,反之在北岸int cabbage(int location){return(0!=(location & 0x02));}//表示羊状态的函数,返回0 ,表示农夫在南岸,反之在北岸int goat(int location){return(0!=(location & 0x01));}其中,location 为当前4 种角色所处的状态,其值为0(0000)到15(1111)之间的数。

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

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

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

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

过河有以下规则:(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结构体是为了储图的顶点数与边数,农夫过河问题我采用的是图的深度优先遍历思想。

(2)算法的设计深度优先遍历基本设计思想:设x是当前被访问顶点,在对x做过访问标记后,选择一条从x出发的未检测过的1/12边(x,y)。

若发现顶点y已访问过,则重新选择另一条从x出发的未检测过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过;然后从y开始搜索,直到搜索完从y出发的所有路径,即访问完所有从y出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x出发的未检测过的边。

上述过程直至从x出发的所有边都已检测过为止。

此时,若x不是源点,则回溯到在x之前被访问过的顶点;否则图中所有和源点有路径相通的顶点(即从源点可达的所有顶点)都已被访问过,若图G是连通图,则遍历过程结束,否则继续选择一个尚未被访问的顶点作为新源点,进行新的搜索过程。

程序中的深度优先遍历算法如下:void dfsPath(AdjGraph *graph, int start, int end) // 深度优先搜索从u到v的简单路径//DFS--Depth First Search{int i = 0;visited[start] = true; //标记已访问过的顶点if (start == end){return ;}for (i = 0; i < graph->vertexNum; i++){if (graph->Edge[start][i] && !visited[i]){retPath[start] = i;dfsPath(graph, i, end);}}}(3)抽象数据类型设计int locate(AdjGraph *graph, int farmer, int wolf, int sheep, int veget) // 查找顶点(F,W,S,V)在顶点向量中的位置bool isSafe(int farmer, int wolf, int sheep, int veget) // 判断目前的(F,W,S,V)是否安全bool isConnect(AdjGraph *graph, int i, int j) // 判断状态i与状态j之间是否可转换void printPath(AdjGraph *graph, int start, int end) // 输出从u到v的简单路径,即顶点序列中不重复出现的路径void dfsPath(AdjGraph *graph, int start, int end) // 深度优先搜索从u到v的简单路径 //DFS--Depth First Search四.详细设计1.问题遵循的原则(1)图:顶点和连线的集合,G=(V,E),其中V是图中顶点的有穷非空集合,E是两个顶点的关系的集合,即图中连线的集合。

若E中顶点对<v,u>是有序的,则为有向图,否则为无向图。

(2)网:带权值的图称为网(3)邻接矩阵:表示顶点之间连接关系的矩阵。

2.算法描述(1)深度优先遍历的递归算法:typedef enum{FALSE,TRUE}Boolean;//FALSE为0,TRUE为Boolean visited[MaxVertexNum]; //访问标志向量是全局量void DFSTraverse(ALGraph *G) //深度优先遍历以邻接表表示的图G,而以邻接矩阵表示G时,算法完全与此相同 int i;{for(i=0;i<G->n;i++)visited[i]=FALSE; //标志向量初始for(i=0;i<G->n;i++)if(!visited[i]) //vi未访问过DFS(G,i); //以vi为源点开始DFS搜索}//DFSTraverse(2)邻接矩阵表示的深度优先遍历算法:void DFSM(MGraph *G,int i) //以vi为出发点对邻接矩阵表示的图G进行DFS搜索,设邻接矩阵是0,l矩阵 int j;{printf("visit vertex:%c",G->vexs[i]);//访问顶点vivisited[i]=TRUE;for(j=0;j<G->n;j++) //依次搜索vi的邻接点if(G->edges[i][j]==1&&!visited[j])DFSM(G,j)//(vi,vj)∈E,且vj未访问过,故vj为新出发点}//DFS五.运行与测试1.程序清单#include<iostream>using namespace std;#define VertexNum 100 //最大顶点数typedef struct // 图的顶点{int farmer; // 农夫int wolf; // 狼int sheep; // 羊int veget; // 白菜}Vertex;typedef struct{int vertexNum; // 图的当前顶点数Vertex vertex[VertexNum]; // 顶点向量(代表顶点)bool Edge[VertexNum][VertexNum]; // 邻接矩阵. 用于存储图中的边,其矩阵元素个数取决于顶点个数,与边数无关}AdjGraph; // 定义图的邻接矩阵存储结构bool visited[VertexNum] = {false}; // 对已访问的顶点进行标记(图的遍历)int retPath[VertexNum] = {-1}; // 保存DFS搜索到的路径,即与某顶点到下一顶点的路径// 查找顶点(F,W,S,V)在顶点向量中的位置int locate(AdjGraph *graph, int farmer, int wolf, int sheep, int veget){// 从0开始查找for (int i = 0; i < graph->vertexNum; i++){if ( graph->vertex[i].farmer == farmer && graph->vertex[i].wolf == wolf && graph->vertex[i].sheep == sheep && graph->vertex[i].veget == veget ){return i; //返回当前位置}}return -1; //没有找到此顶点}// 判断目前的(F,W,S,V)是否安全bool isSafe(int farmer, int wolf, int sheep, int veget){//当农夫与羊不在一起时,狼与羊或羊与白菜在一起是不安全的if ( farmer != sheep && (wolf == sheep || sheep == veget) ){return false;}else{return true; // 安全返回true}}// 判断状态i与状态j之间是否可转换bool isConnect(AdjGraph *graph, int i, int j){int k = 0;if (graph->vertex[i].wolf != graph->vertex[j].wolf){k++;}if (graph->vertex[i].sheep != graph->vertex[j].sheep){k++;}if (graph->vertex[i].veget != graph->vertex[j].veget){k++;}// 以上三个条件不同时满足两个且农夫状态改变时,返回真, 也即农夫每次只能带一件东西过桥if (graph->vertex[i].farmer != graph->vertex[j].farmer && k <= 1){return true;}else{return false;}}// 创建连接图void CreateG(AdjGraph *graph){int i = 0;int j = 0;// 生成所有安全的图的顶点for (int farmer = 0; farmer <= 1; farmer++){for (int wolf = 0; wolf <= 1; wolf++){for (int sheep = 0; sheep <= 1; sheep++){for (int veget = 0; veget <= 1; veget++){if (isSafe(farmer, wolf, sheep, veget)){graph->vertex[i].farmer = farmer;graph->vertex[i].wolf = wolf;graph->vertex[i].sheep = sheep;graph->vertex[i].veget = veget;i++;}}}}}// 邻接矩阵初始化即建立邻接矩阵graph->vertexNum = i;for (i = 0; i < graph->vertexNum; i++){for (j = 0; j < graph->vertexNum; j++){// 状态i与状态j之间可转化,初始化为1,否则为0if (isConnect(graph, i, j)){graph->Edge[i][j] = graph->Edge[j][i] = true;}else{graph->Edge[i][j] = graph->Edge[j][i] = false;}}}return;}// 判断在河的那一边char* judgement(int state){if (state==0)return("南岸");elsereturn("北岸");// return ( (0 == state) ? "南岸" : "北岸" );}// 输出从u到v的简单路径,即顶点序列中不重复出现的路径void printPath(AdjGraph *graph, int start, int end){int i = start;cout << "farmer" << ", wolf" << ", sheep" << ", veget" << endl;while (i != end){cout << "(" << judgement(graph->vertex[i].farmer) << ", " << judgement(graph->vertex[i].wolf)<< ", " << judgement(graph->vertex[i].sheep) << ", " << judgement(graph->vertex[i].veget) << ")";cout << endl;i = retPath[i];}cout << "(" << judgement(graph->vertex[i].farmer) << ", " << judgement(graph->vertex[i].wolf)<< ", " << judgement(graph->vertex[i].sheep) << ", " << judgement(graph->vertex[i].veget) << ")";cout << endl;}// 深度优先搜索从u到v的简单路径 //DFS--Depth First Searchvoid dfsPath(AdjGraph *graph, int start, int end){int i = 0;visited[start] = true; //标记已访问过的顶点if (start == end){return ;}for (i = 0; i < graph->vertexNum; i++){if (graph->Edge[start][i] && !visited[i]){retPath[start] = i;dfsPath(graph, i, end);}}}int main(){AdjGraph graph;CreateG(&graph);int start = locate(&graph, 0, 0, 0, 0);int end = locate(&graph, 1, 1, 1, 1);dfsPath(&graph, start, end);if (visited[end])// 有结果{printPath(&graph, start, end);return 0;}return -1;}2.运行结果六.总结与心得这次的编程让我受益良多,从一窍不通到现在自己完成课设题目,觉得自己进步了一点。

相关文档
最新文档