图的深度优先遍历实现农夫过河

    xiaoxiao2023-11-02  159

                                          数据结构课程设计报告

     

                                                           农夫过河

     

     

     

     

     

     

     

     

                                                                                                                         学号:     xxxxxxxxxx     

                                                                                                                          姓名:          xxx             

                                                                                                                         专业:         xxxxxx         

                                                                                                                         班级:      xxxxxxxxx      

                                                                                                                         指导教师:     xx        

                                                                                                                         完成日期:   2018年6月

     

    一、问题描述:

    要求设计实现农夫过河问题(农夫带着一只狼,一只羊,一棵白菜,一次只能带一个东西)如何安全过河。

    船上一次只能带一个东西,只有农夫会划船。当农夫不在时,狼如果和羊在一起,狼会把羊吃掉,羊不能和白菜在一起,羊会把白菜吃掉。但是狼不吃白菜。试求通过计算,得到能够使农夫,狼,羊,白菜一起安全过河的方法。

     

    问题的解决方案:

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

    实现四个过河对象(农夫、白菜、羊和狼)的状态,可以用一个四位二进制数来表示,0表示未过河,1表示已经过河了。过河的对象必须与农夫在河的同一侧,可以设计函数来判断。防止状态往复,即农夫将一个东西带过去又带回来的情况发生,需将所有可能的状态进行标定。可用深度优先搜索算法及广度优先搜索算法去解题。在基本要求达到后,可进行创新设计,如系统用户功能控制,改进算法的实现,实现友好的人机交互等等。

     

    二、系统设计

     

    1.功能实现概括:

           在实现农夫过河中,我采用了无向图的结构来存储结点信息,用邻接矩阵存储结点的关系,用一个四位二进制数来表示过河状态,0表示河北岸,1表示从河南岸,初始状态农夫、狼、羊、白菜都在河北岸,用0000表示。完全过河后用1111表示。

           图的遍历过程采用了深度优先搜素算法,将遍历的过程存入一个数组来记录过河过程,经过系统分析,农夫过河有两种解答方式,由于深度优先算法是遍历所有结点,造成数组部分被覆盖,在第二次遍历时改动了一些算法结构,使得第二种过河方式得以保存实现。

     

     

    2.程序功能模块:

           该系统分为三大模块

           第一块:将农夫、狼、羊、白菜作为图的结点元素构建图的结点结构体,构造邻接矩阵,构造图时先判断结点的安全状态,创建只有安全结点,再判断各个结点之间的联系,将有关系的边存入邻接矩阵,构造图的结构。

     

           第二块:利用深度优先搜索算法进行图的遍历,遍历到一个结点时,判断寻找与其有关系的下一个结点,将下一个结点的下标存入设定的ray数组,数组存放的既是过河过程。第二次遍历时,为避免深度优先搜素算法使得存入部分下标被覆盖,在可能被覆盖的结点进行算法改动,将另一种过程存入预定的ray2数组,从而实现两种过河过程。

     

           第三块:分别循环访问ray和ray2数组, 判断数组元素对应的下标结点,打印出对应的过河过程和河两岸的对象状态,最后输出总的过河过程。

     

    3.系统流程图

     

    (1)图的结构:

           因为从初始状态0000到1111一共有16种情况,判断其安全的情况共有十种,再判断各个结点的连接关系,运用邻接矩阵构建图的结构

    (2)流程图:

             略

    4.系统的功能调试

     

                本程序不需要用户输入,只需要用户按回车键即可观察下一步的操作即可。通过一定的界面友好的展示给用户正确的过程。

    这是第一种过河方式

    这是第二种过河方式

    两种过河方式在第三步,第四步,第五步有所不同

    详细代码如下:

    #include <iostream> #include <windows.h> #include <stdio.h> using namespace std; #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define MAXSIZE 16 #define INFINTITY 65535 int visited[MAXSIZE]; int ray[MAXSIZE]; int ray2[MAXSIZE]; static int sum =0; typedef int EdgeType; /*状态顶点*/ typedef struct { int farmer; //农夫 int wolf; //狼 int sheep; //羊 int cabbage; //白菜 }status; /*邻接矩阵结点*/ typedef struct { int stanum; //顶点个数 status vexs[MAXSIZE]; //储存顶点数组 EdgeType arc[MAXSIZE][MAXSIZE]; //邻接矩阵权值 }MGraph; /*判断该状态是否安全*/ int isSafe(int farmer,int wolf,int sheep,int cabbage) { //狼羊同岸 或 羊菜同岸 if(((farmer!=wolf)&&(wolf==sheep))||((farmer!=sheep)&&(sheep==cabbage))) return FALSE; else return TRUE; } /*判断两个点是否有联系*/ int Truemove(MGraph G,int i,int j) { int change = 0; if(G.vexs[i].farmer==G.vexs[j].farmer) //判断农夫是否移动 return FALSE; else if(G.vexs[i].wolf!=G.vexs[j].wolf) //狼 change++; if(G.vexs[i].sheep!=G.vexs[j].sheep) //羊 change++; if(G.vexs[i].cabbage!=G.vexs[j].cabbage) //白菜 change++; if(change>1) return FALSE; else return TRUE; } /*创建只有安全结点的图*/ void CreateUDG(MGraph &G) { G.stanum=0; //将判断安全的状态存入数组 10种 for(int i=0;i<=1;i++) { for(int j=0;j<=1;j++) { for(int k=0;k<=1;k++) { for(int l=0;l<=1;l++) { if(isSafe(i,j,k,l)) { G.vexs[G.stanum].farmer=i; G.vexs[G.stanum].wolf=j; G.vexs[G.stanum].sheep=k; G.vexs[G.stanum].cabbage=l; G.stanum++; } } } } } //将有关系的边存入邻接矩阵 构建图的结构 for(int i = 0;i < G.stanum;i++) { for(int j = 0;j< G.stanum;j++) { if(Truemove(G,i,j)) { G.arc[i][j] = TRUE; } else { G.arc[i][j] = INFINTITY; } } } } /*邻接矩阵的深度优先递归算法*/ void DFS(MGraph G,int i,int a) { if(a==1) { visited[i] = TRUE; //cout<<i<<" "; //cout<<G.vexs[i].farmer<<G.vexs[i].wolf<<G.vexs[i].sheep<<G.vexs[i].cabbage<<endl; if(i==9) return; for(int j=0;j<G.stanum;j++) if(G.arc[i][j] != INFINTITY && !visited[j]) { ray[i] = j; //cout<<j<<" "; DFS(G,j,a); } } else if(a==2) { visited[i] = TRUE; //cout<<i<<" "; //cout<<G.vexs[i].farmer<<G.vexs[i].wolf<<G.vexs[i].sheep<<G.vexs[i].cabbage<<endl; if(i==9) return; for(int j=0;j<G.stanum;j++) if(G.arc[i][j] != INFINTITY && !visited[j]) { if(j==1||j==6){ continue; } ray2[i] = j; //cout<<j<<" "; DFS(G,j,a); } } } /*邻接矩阵的深度优先遍历算法*/ void TraverseDFS(MGraph G,int a) { if(a==1) { for(int i = 0;i<G.stanum;i++) { visited[i] = FALSE; ray[i] = -1; } for(int i=0;i<G.stanum;i++) if(!visited[i]) //对未访问过的顶点调用DFS 若是连通图的话,只会执行一次 DFS(G,i,a); } else if(a==2) { for(int i = 0;i<G.stanum;i++) { visited[i] = FALSE; ray2[i] = -1; } for(int i=0;i<G.stanum;i++) if(!visited[i]) //对未访问过的顶点调用DFS 若是连通图的话,只会执行一次 DFS(G,i,a); } } /*查找下标*/ int find(MGraph G,int farmer,int wolf,int sheep,int cabbage) { for (int i = 0; i < G.stanum; i++) { if (G.vexs[i].farmer == farmer && G.vexs[i].wolf == wolf && G.vexs[i].sheep == sheep && G.vexs[i].cabbage == cabbage ) { return i; //返回当前位置 } } return -1; } /*展示面板*/ void showTable1() //船在上 { cout<<"========================================================================================================================"<<endl; cout<<" << 船 # * - - "<<endl; cout<<" / \\ * * - "<<endl; cout<<" \\ / "<<endl; cout<<" << * - - "<<endl; cout<<" * * "<<endl; cout<<" * - - "<<endl; cout<<" << * * "<<endl; cout<<" "<<endl; cout<<" * * - "<<endl; cout<<" << * - - "<<endl; cout<<"========================================================================================================================"<<endl; } void showTable2() //船在下 { cout<<"========================================================================================================================"<<endl; cout<<" << * - - "<<endl; cout<<" * * - "<<endl; cout<<" "<<endl; cout<<" <<- - "<<endl; cout<<" * * "<<endl; cout<<" * - - "<<endl; cout<<" << # * * "<<endl; cout<<" / \\ "<<endl; cout<<" \\ / * * - "<<endl; cout<<" << 船 * * - - "<<endl; cout<<"========================================================================================================================"<<endl; } void showPeole1(MGraph G,int i)//北方的状态 { cout<<" 北方"<<" "; if(G.vexs[i].farmer==0) cout<<"\t农夫"; if(G.vexs[i].wolf==0) cout<<"\t狼"; if(G.vexs[i].sheep==0) cout<<"\t羊"; if(G.vexs[i].cabbage==0) cout<<"\t白菜"; cout<<endl; } void showPeole2(MGraph G,int i)//南方的状态 { cout<<" 南方"<<" "; if(G.vexs[i].farmer==1) cout<<"\t农夫"; if(G.vexs[i].wolf==1) cout<<"\t狼"; if(G.vexs[i].sheep==1) cout<<"\t羊"; if(G.vexs[i].cabbage==1) cout<<"\t白菜"; cout<<endl; } /*加入叙述语句*/ void saySomething(MGraph G,int i,int a) { if(a==1) { int wolf = 0, sheep = 0, cabbage = 0; if(sum!=0) { cout<<"\n\n\t第"<<sum<<"步:\t"; if(G.vexs[ray[i]].wolf != G.vexs[i].wolf) { if(G.vexs[ray[i]].farmer == 1) cout<<"农 夫 带 狼 去 了 南 边 "<<endl; else cout<<"农 夫 带 狼 去 了 北 边 "<<endl; } else if(G.vexs[ray[i]].sheep != G.vexs[i].sheep) { if(G.vexs[ray[i]].farmer == 1) cout<<"农 夫 带 羊 去 了 南 边 "<<endl; else cout<<"农 夫 带 羊 去 了 北 边 "<<endl; } else if(G.vexs[ray[i]].cabbage != G.vexs[i].cabbage) { if(G.vexs[ray[i]].farmer == 1) cout<<"农 夫 带 白 菜 去 了 南 边 "<<endl; else cout<<"农 夫 带 白 菜 去 了 北 边 "<<endl; } else { if(G.vexs[ray[i]].farmer == 1) cout<<"农 夫 独 自 去 了 南 边 "<<endl; else cout<<"农 夫 独 自 去 了 北 边 "<<endl; } } sum++; } else if(a==2) { int wolf = 0, sheep = 0, cabbage = 0; if(sum!=0) { cout<<"\n\n\t第"<<sum<<"步:\t"; if(G.vexs[ray2[i]].wolf != G.vexs[i].wolf) { if(G.vexs[ray2[i]].farmer == 1) cout<<"农 夫 带 狼 去 了 南 边 "<<endl; else cout<<"农 夫 带 狼 去 了 北 边 "<<endl; } else if(G.vexs[ray2[i]].sheep != G.vexs[i].sheep) { if(G.vexs[ray2[i]].farmer == 1) cout<<"农 夫 带 羊 去 了 南 边 "<<endl; else cout<<"农 夫 带 羊 去 了 北 边 "<<endl; } else if(G.vexs[ray2[i]].cabbage != G.vexs[i].cabbage) { if(G.vexs[ray2[i]].farmer == 1) cout<<"农 夫 带 白 菜 去 了 南 边 "<<endl; else cout<<"农 夫 带 白 菜 去 了 北 边 "<<endl; } else { if(G.vexs[ray2[i]].farmer == 1) cout<<"农 夫 独 自 去 了 南 边 "<<endl; else cout<<"农 夫 独 自 去 了 北 边 "<<endl; } } sum++; } } /*打印全部操作*/ void sayall(MGraph G,int i,int end,int a) { if(a==1) { sum = 1; cout<<"\n\n\n第一种总路程为:"<<endl; while(i!=end) { cout<<endl; saySomething(G,i,a); i = ray[i]; } getchar(); system("cls"); } else if(a==2) { sum = 1; cout<<"\n\n\n第二种总路程为:"<<endl; while(i!=end) { cout<<endl; saySomething(G,i,a); i = ray2[i]; } getchar(); system("cls"); } } /*展示总面板*/ void showAll(MGraph G,int start,int end,int a) { if(a==1) { cout<<" 农夫过河《一》"<<endl<<endl; int low = start; while(start!=end) { showPeole1(G,start); //北 if(G.vexs[start].farmer==0) showTable1(); else showTable2(); showPeole2(G,start); //南 saySomething(G,low,a); low = start; start=ray[start]; getchar(); system("cls"); } showPeole1(G,start); if(G.vexs[start].farmer==0) showTable1(); else showTable2(); showPeole2(G,low); saySomething(G,low,a); start=find(G,0,0,0,0);//重置下标 getchar(); system("cls"); } else if(a==2) { cout<<" 农夫过河《二》"<<endl<<endl; sum=0; int low = start; while(start!=end) { showPeole1(G,start); //北 if(G.vexs[start].farmer==0) showTable1(); else showTable2(); showPeole2(G,start); //南 saySomething(G,low,a); low = start; //cout<<"start="<<start<<endl;//测试遍历过程下标 start=ray2[start]; getchar(); system("cls"); } showPeole1(G,start); if(G.vexs[start].farmer==0) showTable1(); else showTable2(); showPeole2(G,start); saySomething(G,low,a); start=find(G,0,0,0,0);//重置下标 getchar(); } } int main() { MGraph G; CreateUDG(G); int start = find(G,0,0,0,0); int end = find(G,1,1,1,1); TraverseDFS(G,1); //第一种遍历答案 TraverseDFS(G,2); //第二种遍历答案 showAll(G,start,end,1);//第一种过河方式 sayall(G,start,end,1);//输出第一种过河过程 showAll(G,start,end,2);//第二种过河方式 sayall(G,start,end,2);//输出第二种过河过程 }

    如有错误,欢迎指出。

    最新回复(0)