一、需求分析
1.问题描述:
一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。他要把这些东西全部运到北岸。他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。
2.基本要求:
(1)利用图的存储结构
(2)图的搜索算法
(3)求出农夫将所有的东西运过河的所有方案
6.农夫过河问题
一、需求分析
1.问题描述:
一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。他要把这些东西全部运到北岸。他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。
2.基本要求:
(1)利用图的存储结构
(2)图的搜索算法
(3)求出农夫将所有的东西运过河的所有方案
二、设计
1. 设计思想
(1)存储结构
以邻接矩阵存储合理状态,用一个一维数组保存所有的方案;
(2)主要算法基本思想
人,狼,羊和白菜共有2的四次方16种状态(河岸的状态可由人的状态确定),去掉不允许出现的6种状态,10个状态对应矩阵的10个结点值,然后根据状态的连续改变初始化矩阵,接着就用递归的深度优先法搜索所有的路径,即求出过河的方案。
|
2. 设计表示
(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)//辅助:邻接矩阵输出,用于观察搜索的过程。
void Ch(int i) //将状态转换为汉字的方案输出
3. 详细设计(主要函数)
【1】int Judge(int a,int b)
将十进制的16种状态分别转换为二进制的数存在一维数组中
判断:
人不在时,羊狼,羊菜不能再一起
从而初始化了矩阵的结点值
【2】Initiate(&graph,k);
通过Judge函数判断可以连续变化的状态
在Judge中人的状态必须一次一遍,而其他东西的状态,最多变一个。根据其返回值将矩阵初始化。
【3】DFS(AdjMGraph *G,Path *path,int x,int t)
递归的深度优先搜索法
int a=0;//遍寻下一条路径
int DFS(AdjMGraph *G,Path *path,int x,int t)
{
int i;
int k,p,m;
Push(path,x);//遍历过的点入栈
p=0;
k=0; //路径未遍历完
for(i=t;i<N;i++) //搜相关联的顶点
if(G->edge[i][x]>0)
{
k=1;
G->edge[i][x]=0;
G->edge[x][i]=0; //此边已访问,删除此边
DFS(G,path,i,0);//找到的是与x关联的i,寻找下一条关联的边
break;
}
if(k==0) //遍历完当前顶点关联的边
{
printfpath(path);
while(path->top!=0&&p==0&&a<N-1)//a为点数减1
{
GetTop(path,&m);
Top(path,&x); for(i=0;i<N;i++)
if(G->edge[i][x]>0)
{
p=1;
k=1; //一条路径未遍历完
if(x==0) //从新开始遍历
{
G->edge[x][m]=1;
G->edge[m][x]=1;
GetTop(path,&x);
}
G->edge[x][m]=1;G->edge[m][x]=1;
a=++m;//如果可能的话,从当前节点的下一条关联边开始搜寻
GetTop(path,&x);
DFS(G,path,x,a);//x被入栈
break;
}
G->edge[x][m]=1;G->edge[m][x]=1;//恢复在上一层中被删除的边
}
}
return 0;
}
三、调试分析
1.调试过程中遇到的主要问题是如何解决的;
该题有两大难点,一是:矩阵的合理逻辑构建
二是:两条方案的搜出
刚开始由于平常做ACM题图论的影响,没有正确把握题意,曲解了题意,在老师的提示下正确的理解了题意。
由于搜图函数已在理解错误下正确写出,所以分析了如何逻辑构图之后,问题很容易就得到解决。在老师的指导下,程序越来越完善。
2.对设计和编码的回顾讨论和分析;
在遇到每个问题的时候,一定要认真冷静的分析题意,以免通过过往经验而误读题意,最后导致与正确结果南辕北辙的后果。
弄懂题意后,要先从程序的整体入手,分析写程序的难点所在,然后联系所学找到可能解决的途径,选出最佳的方法攻破难点。
最后还等考虑程序的安全性,尤其是健壮性的问题,使程序更加的完善,如有可能最好能解决题目之外类似的问题。
3.时间和空间复杂度的分析;
【1】:图的初始化算法 时间O(n*n),空间O(1)
【2】:图的搜索算法 时间O(n*n), 空间O(1)
4.改进设想;
程序能实现预期功能,可有改进空间
【1】:图更简洁初始化方法
【2】:更能解决一般性的问题
5.经验和体会等。
多参加有益的比赛,科研,动手编程,才能熟练灵活的掌握C语言基础知识,才能更好的理解掌握数据结构的精髓。从而避免基础语法错误,让代码变得更简洁高效。如此才能准确高效的解决问题。
四、用户手册(即使用说明)
仅需按照提示的输入即可。若出错,则重新来过。
五、运行结果
运行环境:codeblocks
测试用表:1 2 3 4
0 1 2 3
1 2 2 3
运行后的界面
测试数据:1 2 3 4
**输入不符合要求或不满足题意时,无法输出正确结果
****在输入完后,核对输入是否符合题意,如若不然提示出错,重新输入
(已改正)测试数据:1 2 3 4
正确测试数据:1 2 2 3
六、源程序清单
https://wenku.baidu.com/view/7263c7048ad63186bceb19e8b8f67c1cfbd6ee39