农夫过河报告(最终版)

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

农夫过河算法实验报告
――数据结构项目课研究课题
组长:崔俊
组员:李琦、郑鸿飞、王琅辉、张育博
15.12.29
摘要
农夫过河问题是应用广度优先搜索和深度优先搜索的典型问题,但这里我们应用了简单
的数组,通过层层筛选的手段也解决了同样的问题,其中用到了部分广度优先搜索的思想。

、八■、-
前言
农夫过河问题描述:一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸。

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

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

如果农夫在场,则狼不能吃羊,羊不能吃白菜,否则狼会吃羊,羊会吃白菜,所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。

请求出农夫
将所有的东西运过河的方案。

正文
1∙问题抽象和数据组织
农夫过河问题应该应用图的广度优先遍历或者深度优先遍历,但这里我们仅使用简单的
线性表一一数组,通过多重的条件限制,达成目的。

这里我们同样用O和1代表农夫、狼、
羊、白菜在左岸还是在右岸,并规定O在左,1在右,我们的目的便是从OOOO通过一系列变换到1111。

2.农夫过河算法源代码
#in elude VStdio.h>
#define MAX 16
typedef StrUCt FWSV
{
int farmer;
int wolf;
int sheep;
int vegetable;
}Item;
//函数原型
//操作:筛选符合条件的安全的数组成员
//操作前:无
//操作后:返回安全数组的指针
void SCree n( void);
//操作:判断下一个数应该取安全数组中那个数
//操作前:传递一个结构体数组成员
//操作后:返回另一个结构体数组指针
Item * judge(Item Fwsv);
Item safe[MAX];
int k = 0;
int main (Void)
{
SCree n();
Item * n ext;
Item first,sec On d,e nd;
first = safe[0];
end = safe[k];
Prin tf("first:0000\n"); n ext = judge(first);
void SCree n( void)
{
int f = 0,w = 0,s = 0,v = 0;
for(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 Il S == V)))
{
safe[k].farmer = f;
safe[k].wolf = w;
safe[k].sheep = s;
safe[k].vegetable = v;
k++;
// 用于计数safe[]中的总数
}
}
}
}
}
}
Item * judge(Item FWSV)
{
Item * n ext;
Item COmPare[4];
n ext = compare;
int x1 = 0;
int SUm = 0;
if (Fwsv.farmer == 0)
{
for (int X = 0;X < k;x++)
{
ZZ把出现过的置零操作
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;
}
ZZ筛选出农夫状态值与之前相反的1变0 0变1
if(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 = Fwsvfarmer + 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)
{
Il (Fwsv.farmer != Fwsv.vegetable && COmPare[x2].VegetabIe !
= Fwsv.vegetable)
Il (Fwsv.farmer != Fwsv.vegetable && COmPare[x2].VegetabIe !
= Fwsv.vegetable))
{
COmPare[x2].farmer = 0;
COmPare[x2].wolf = 0;
COmPare[x2].SheeP = 0;
COmPare[x2].VegetabIe = 0;
}
sum+=2;
//对和的限制
if(compare[x2].farmer + COmPare[x2].wolf + COmPare[x2].SheeP +
COmPare[x2].VegetabIe != SUm)
{
COmPare[x2].farmer = 0;
COmPare[x2].wolf = 0;
COmPare[x2].SheeP = 0;
COmPare[x2].VegetabIe = 0;
}
}
Printf(" -------------------------------------- ∖n");
for(i nt x3 = 0;x3 < 4;x3++)
{
if (COmPare[x3].farmer + COmPare[x3].wolf + COmPare[x3].SheeP +
COmPare[x3].VegetabIe != 0)
{
Printf(" 上数与:%d%d%d%d 连∖n",
ComPare[x3].farmer,compare[x3].wolf,compare[x3].sheep,compare[x3].veget abl );
}
{
if (Fwsv.farmer == 1) {
for (int y = 0;y V 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.sheep)
Fwsv.vegetable)
Fwsv.vegetable))
{
COmPare[x2].farmer = 0; COmPare[x2].wolf = 0; COmPare[x2].SheeP = 0; COmPare[x2].VegetabIe = 0; } }
Printf(" for(i nt x3 = 0;x3 < 4;x3++)
∣∣(Fwsv.farmer != Fwsv.sheep && COmPare[x2].SheeP
!= Il (Fwsv.farmer
!= Fwsv.vegetable && COmPare[x2].VegetabIe != Il (Fwsv.farmer
!= Fwsv.vegetable
&& COmPare[x2].VegetabIe
!=
∖n");
if (ComPare[x3].farmer + ComPare[x3].Wolf + ComPare[x3].SheeP + ComPare[x3].VegetabIe != 0)
{
Printf(" 上数与:%d%d%d%d 连∖n",
ComPare[x3].farmer,compare[x3].wolf,compare[x3].sheep,compare[x3].vegetable
);
}
}
}
return n ext;
}
3. 算法功能说明和流程描述
首先我们定义了一个结构体Item
typedef StrUCt FWSV
{
int farmer;
int wolf;
int sheep;
int vegetable;
}Item;
Item 中包含了农夫(farmer ),狼(wolf ),羊(SheeP),白菜(VegetabIe ),用来表示农夫、狼、羊、白菜的状态,并作出规定当为0的时候表示在左岸,当为1的时候表示在右岸,我们的目标便是从0000的状态到1111的状态。

接下来用一个调用函数SCreen ()
void SCree n( void)
{
int f = 0,w = 0,s = 0,v = 0;
for(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 Il S == V)))
{
safe[k].farmer = f;
safe[k].wolf = w;
safe[k].sheep = s;
safe[k].vegetable = v;
k++;
}
}
}
}
}
}
函数一连用了4个for循环完成了对0000到1111之间每一位数字的所有排列组合的遍历,虽然这里的时间复杂度直接跃至0(n4)但却是比较全面、写法简单的遍历,而且n仅为2,其中的if语句的判断从所有的排列组合中(总计16种)剔除了不会出现的组合,其中包括:农夫不在,羊吃白菜,狼吃羊等情况。

并让符合条件的情况存入了全局变量数组safe[MAX]中。

Item * judge(ltem FWSV) 函数是整个算法的核心,思想比较简单但写法繁琐,目的是
判断safe[k]数组中符合如题条件的数值,它的参数是上一次的状态值,对于初始时便为0000,它的返回值是一个符合条件的数值的数组首地址next ,为了防止有多解的情况我们
把符合条件的值存入了一个COmPare[4]数组,如果为单解则将COmPare中其他成员置零,接下来我们拆分着看看这个函数。

if (Fwsv.farmer == 0) 表示农夫现在在左岸接下来的for循环是对safe[k]数组的遍
历,目的是第一轮找出符合条件的值
for (int X = 0;X < k;x++)
{
//这里的if判断是把出现过的值在safe[k]中置零的操作,为了进一步方便判断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;
}
//从safe[k]中筛选出农夫状态值与之前相反的并存入COmPare数组中。

因为只有农夫会划船,所以来回农夫的状态必定改变,比如传进来的是0打头的传输出去的必定是1打头
的。

我们要做的就是从safe[k]中找出农夫状态值与之前相反的数值,总计5个,其中我们把1111的情况也要剔除掉,现在总计4个了,我们把符合要去的数值从16个缩减到10个现在又缩减到4个,接下来我们还要缩减
if(safe[x].farmer == 1 && (safe[x].farmer + safe[x].wolf + safe[x].sheep + safe[x].vegetable != 4 )) {
COmPare[x1] = safe[x]; x1++; }
}
ZZ 这里的for 便是对COmPare 的遍历了 for (int x2 = 0;x2 < 4;x2++) {
ZZ 上述缩减到4个但是范围还是太大,现在置零状态值与农夫不同但是改变了的。

SUm = Fwsv.farmer + Fwsv.wolf + Fwsv.sheep + Fwsv.vegetable; if ((FWSV.farmer != Fwsv.wolf && COmPare[x2].wolf != Fwsv.wolf) II(FWSV.farmer != Fwsv.sheep && COmPare[x2].SheeP != Fwsv.sheep) Il (Fwsv.farmer != Fwsv.vegetable && COmPare[x2].VegetabIe Il (Fwsv.farmer != Fwsv.vegetable && COmPare[x2].VegetabIe
COmPare[x2].farmer = 0; COmPare[x2].wolf = 0; COmPare[x2].SheeP = 0; COmPare[x2].VegetabIe = 0; } sum+=2;
ZZ 由于船一次只能拉不超过两个, 其中一个还要是农夫划船,所以这里我们对和有一个 限制。

当农夫拉着东西从左岸划向右岸时,总的状态值之和应该等于上一个状态 +现在的状 态,而现在的状态和必定为 2,所以sum+=2这里我们举个例子就明白了: 0000开始,农夫
拉着羊从左岸到右岸变成
1010 (此时的状态和为 2),之后农夫划船回来变成
0010 (此时
状态值为1),接着农夫划船拉着狼从左至右变成
1110(此时状态和为3, 3 = 1 + 2)......
if (Compare[x2].farmer + COmPare[x2].wolf
+
COmPare[x2].SheeP
+
COmPare[x2].VegetabIe != SUm) {
COmPare[x2].farmer = 0; COmPare[x2].wolf = 0; COmPare[x2].SheeP = 0; COmPare[x2].VegetabIe = 0; } }
Printf(" -------------------------------------- ∖n");
也就是说如果之前与农夫状态值相同,
说明和农夫在相同一侧的岸,
变的机会,要是与农夫之前与农夫状态值不同,说明和农夫相处对岸, 是不符合逻辑的,狼,羊,白菜是不会自己游过河的。

这时它才有可能改 这时它改变了, 显然
!= Fwsv.vegetable) != Fwsv.vegetable))
ZZ通过上述三种限制,我们已经可以判断出safe[k]中完全符合要求的数值了,可能有
一个,可能有两个,也可能多个,接下来的for遍历COmPare并打印我们需要的结果for(int x3 = 0;x3 < 4;x3++)
{
if (COmPare[x3].farmer + COmPare[x3].wolf + COmPare[x3].SheeP +
COmPare[x3].VegetabIe != 0)
{
Prin tf("上数与:%d%d%d%d连\n",
ComPare[x3].farmer,compare[x3].wolf,compare[x3].sheep,compare[x3].vegetabl
)
}
}
}
if (Fwsv.farmer == 1)
{
/*表示农夫现在在右岸接下来的for循环是对safe[k]数组的遍历,目的是第一轮找出
符合条件的值,与Fwsv.farmer == 0 的情况一样,判断方法与条件也完全相同,只不过对
于0打头的情况省去了对和的限制这一条件*/
}
4. 算法实现与验证
首先0000传入judge函数,返回1010,表示0000与1010相连,接下来1010传入, 返回0010,现在0000----1010----0010 ,接下来0010传入,返回1011和1110两个,表示0000----1010----0010----1011 和1110,我们只取第一个,1011 传入,返回0001,传入0001 ,返回1101 ,现在是OOOO----1010----0010----1011 (还有1110)----0001----1101 ,接下来传入
1101 ,返回0100和0101 ,同理只取第一个,传入0100,返回1110 ,至此结束整个传递,到达1111的状态
这些数字看着有些不清晰,我们来整理下
0000——1010一0010-—-1011 ——0001——Iol-——0100
OlOI
整理得
OOOO --- IOIo一0010—IOr ——OoOI——101 ---------- 0101 —1111
------ OIOO-^
通过图示我们发现农夫过河有两种解
(1)农夫、狼、羊、白菜开始都在左岸0000,农夫拉羊从左岸到右岸1010,农夫自己从右岸到左岸0010,农夫拉着白菜从左岸到右岸1011,农夫把羊从右岸拉回左岸0001,农夫拉着狼从左岸到右岸1101 ,农夫自己从右岸到左岸0101 ,农夫拉着羊从左岸到右岸1111。

(2)农夫、狼、羊、白菜开始都在左岸0000,农夫拉羊从左岸到右岸1010 ,农夫自己
从右岸到左岸0010,农夫拉着狼从左岸到右岸1110,农夫把羊从右岸拉回左岸0100,农夫拉着白菜从左岸到右岸1101 ,农夫自己从右岸回到左岸0101 ,农夫拉着羊从左岸到右岸1111。

5. 算法性能分析
本算法性能比较低,因为是一次次遍历,筛选,最后确定符合条件的值。

但算法偏向正
常思维,较简单,且节省了很大内存,整个过程均建立在对safe[k]数组和ComPare[k]的操作。

不过唯一感到不满意的地方是之前为电脑计算了好多,算法的性能还有待优化。

相关文档
最新文档