1 题目

一农夫带着一头狼,一只羊和一担草过河,小船只能一次装载农夫和一样货物,狼会吃羊,羊会吃草,只有农夫在时才安全。现欲让所有物品包括农夫都安全过道河对岸,使用程序实现求解。

2 设计分析

把农夫、狼、羊、草四个按顺序「农夫、狼、羊、草」排列,使用一个布尔数组表示它们的状态,布尔值状态 false 代表对应的人(物)还没有过河,状态 true 代表对应人(物)已经过河了。使用布尔值有个好处,就是当前状态,取反即可得到是过河对面的状态(不管原来是否过河)。

可知初始状态时候它们是:

status[4] = [false, false, false, false]

最终过河后它们的状态应该是[true, true, true, true]

用status[4]数组的一次状态变化前后表示渡河情况,则渡河规则对应成计算机逻辑为:

1)每次过河时候,都需要农夫参与——每次状态改变时候,第0位(注:0下标开始算)必须改变;

2)每次过河只能带一样物品,而且需要农夫来撑船——每次改变时候,第1、2、3位最多只能改变其中1位,变化位情况必须和第0位同步;

3)狼、羊、草三个中, 某一个为另一个食物时候,必须有农夫在场才安全——每次改变后,第1、2、3位中相邻如果相同,则必须和第0位相同。

根据这规则,使用数组作为当前状态根节点,生成了后续所有状态,再对后续的情况再做情况枚举,便可得到一棵数形状态结构:

这棵树中,第3层的右侧那个状态(也就是农夫带羊过去后,再带羊回来)出现和根部结果一样,那么就可以不继续生成其子数了。其他的节点(如第4层最右边的状态),如果出现和父辈某一个节点一样,也是不需要再继续生成(遍历)子树了,因为此状态生成的后续情况必然和之前的状态出现重复局面了。

3 编码

先上流程图:

根据规则,判断一个状态是否是安全的(合法的)——一物为另一物的食物时候,如果它们在河的同一侧,则必须要有农夫在才安全。代码逻辑就是如下了(python代码):

def is_valid_status(status):

if status[1] == status[2]:

if status[0] != status[1]:

# 狼和羊同侧,没有人在场

return False

if status[2] == status[3]:

if status[0] != status[2]:

# 羊和草同侧,没有人在场

return False

return True复制代码

在当前状态,枚举生成下一个状态的所有情况,也就是下一步渡河的所有可行情况。对一个状态取反即是渡河,不管是过去还是回来都是一样——取反即可。代码逻辑如下:

def create_all_next_status(status):

next_status_list = []

for i in range(0, 4):

if status[0] != status[i]: # 和农夫不同一侧?

continue

next_status = [status[0],status[1],status[2],status[3]]

# 农夫和其中一个过河,i 为 0 时候,农夫自己过河。

next_status[0] = not next_status[0]

next_status[i] = next_status[0] # 和农夫一起过河

if is_valid_status(next_status):

next_status_list.append(next_status)

return next_status_list复制代码

树形递归遍历逻辑代码步骤大概如下,

1)在根据当前状态,生成所有下一种状态的所有情况,

2)对生成的状态所有情况进行遍历判断,

(1)如果下一个状态是最终期望状态(都过河了),则输出当前路径结果,

(2)如果下一个状态已经出现过在历史中,则无视,

(3)如果下一个状态是新的状态,把该状态记录到历史中,递归进入步骤1。

搜索代码就是如下了,也就是树形递归遍历逻辑的中心思想(题外话:棋类游戏的递归遍历逻辑也是类似):

def search(history_status):

global scheme_count

current_status = history_status[len(history_status) - 1]

next_status_list = create_all_next_status(current_status)

for next_status in next_status_list:

if next_status in history_status:

# 出现重复的情况了

continue

history_status.append(next_status)

if is_done(next_status):

scheme_count += 1

print("scheme " + str(scheme_count) + ":")

print_history_status(history_status)

else:

search(history_status)

history_status.pop()复制代码

判断是否都过河了,更加简单:

def is_done(status):

return status[0] and status[1] and status[2] and status[3]复制代码

完整代码如下:

#-*- coding: UTF-8 -*-

name = ["farmer", "wolf", "sheep", "grass"]

scheme_count = 0

# 完成局面

def is_done(status):

return status[0] and status[1] and status[2] and status[3]

# 生成下一个局面的所有情况

def create_all_next_status(status):

next_status_list = []

for i in range(0, 4):

if status[0] != status[i]: # 和农夫不同一侧?

continue

next_status = [status[0],status[1],status[2],status[3]]

# 农夫和其中一个过河,i 为 0 时候,农夫自己过河。

next_status[0] = not next_status[0]

next_status[i] = next_status[0] # 和农夫一起过河

if is_valid_status(next_status):

next_status_list.append(next_status)

return next_status_list

# 判断是否合法的局面

def is_valid_status(status):

if status[1] == status[2]:

if status[0] != status[1]:

# 狼和羊同侧,没有人在场

return False

if status[2] == status[3]:

if status[0] != status[2]:

# 羊和草同侧,没有人在场

return False

return True

def search(history_status):

global scheme_count

current_status = history_status[len(history_status) - 1]

next_status_list = create_all_next_status(current_status)

for next_status in next_status_list:

if next_status in history_status:

# 出现重复的情况了

continue

history_status.append(next_status)

if is_done(next_status):

scheme_count += 1

print("scheme " + str(scheme_count) + ":")

print_history_status(history_status)

else:

search(history_status)

history_status.pop()

def readable_status(status, is_across):

result = ""

for i in range(0,4):

if status[i] == is_across:

if len(result) != 0:

result += ","

result += name[i]

return "[" + result + "]"

#打印结果

def print_history_status(history_status):

for status in history_status:

print(readable_status(status, False) + "≈≈≈≈≈≈≈≈≈≈" + readable_status(status, True))

if __name__ == "__main__":

# 初始局面

status = [False, False, False, False]

# 局面队列

history_status = [status]

search(history_status)

print("finish search, find " + str(scheme_count) + " scheme")

复制代码

5 运行结果

由输出结果可知有两种情况:

方案A:

1)农夫带羊过去

2)农夫自己回来

3)农夫带狼过去

4)农夫带羊回来

5)农夫带草过去

6)农夫自己回来

7)农夫带羊过去 方案B:

1)农夫带羊过去

2)农夫自己回来

3)农夫带草过去

4)农夫带羊回来

5)农夫带狼过去

6)农夫自己回来

7)农夫带羊过去

python怎么解题_农夫过河问题 Python实现解题相关推荐

  1. python编程基础_月隐学python第2课

    python编程基础_月隐学python第2课 学习目标 掌握变量的输入和输出 掌握数据类型的基本概念 掌握算数运算 1.变量的输入和输出 1.1 变量输入 使用input输入 input用于输入数据 ...

  2. 查看Python的版本_查看当前安装Python的版本

    一.查看Python的版本_查看当前安装Python的版本 具体方法: 首先按[win+r]组合键打开运行: 然后输入cmd,点击[确定]: 最后执行[python --version]命令即可. 特 ...

  3. python opencv手册_教你用Python实现5毛钱特效(给你的视频来点料)

    一.前言 请务必看到最后.Python牛已经不是一天两天的事了,但是我开始也没想到,Python能这么牛.前段时间接触了一个批量抠图的模型库,而后在一些视频中找到灵感,觉得应该可以通过抠图的方式,给视 ...

  4. python并行运算库_最佳并行绘图Python库简介:“ HiPlot”

    python并行运算库 HiPlot is Facebook's Python library to support visualization of high-dimensional data ta ...

  5. python新手难点_初学两天python的操作难点总结

    已经学习两天python,将我认为的操作难点进行总结 1 在cmd下 盘与盘之间的切换 直接 D或d: 就好 2 查找当前盘或者文件下面的目录 直接 dir 3 想在一个盘下进去一个文件夹,用cd空格 ...

  6. python内存泄漏_诊断和修复Python中的内存泄漏

    python内存泄漏 Fugue uses Python extensively throughout the Conductor and in our support tools, due to i ...

  7. python基本原理概论_怎样开始自学Python?

    本人才疏学浅,学识大多浅尝辄止,故文章若有错误,不论是文字笔误还是理解有错,烦请您留言以告知,本人必定感激不尽! **Python分类下的系列文章,不断更新中,如果你迫不及待地想要看看写得如何可以先试 ...

  8. 如何提高python的运行效率_几个提升Python运行效率的方法之间的对比

    在我看来,python社区分为了三个流派,分别是python 2.x组织,3.x组织和PyPy组织.这个分类基本上可以归根于类库的兼容性和速度.这篇文章将聚焦于一些通用代码的优化技巧以及编译成C后性能 ...

  9. python了解一下_想要精通python?19个语法了解一下!

    原标题:想要精通python?19个语法了解一下! Python简单易学,但又博大精深.许多人号称精通Python,却不会写Pythonic的代码,对很多常用包的使用也并不熟悉.学海无涯,我们先来了解 ...

最新文章

  1. 【转载】 stm32之PWM
  2. 企业根CA方法客户机证书的解决方案,ISA2006系列之三十
  3. 概述VB.NET正则表达式简化程序代码
  4. 分析单点登录cas的解决方式
  5. 软工1816 · Alpha冲刺(9/10)
  6. 通过阅读 Douglas Crockford 的源码学习如何写 JSON parser(一)
  7. MySQL中CREATE DATABASE和CREATE SCHEMA区别(转)
  8. Linux C 算法——查找
  9. Linux下如何编译并运行C程序
  10. 现在Windows Server 2012在Windows Azure 虚拟机库中可用
  11. Docker自定义部署Redis镜像
  12. Linux ALSA音频子系统二
  13. Wyn Enterprise 核心功能:易用至极的自助式BI和数据分析工具
  14. 【CSS】美化网页元素+盒子模型
  15. 树莓派配置文件config.txt详细介绍
  16. Apollo搭建使用
  17. 转载_纯Java代码批量去除图片文字水印
  18. 天池AI学习全面升级,所有学习资源都给你你汇总好啦!
  19. 计算机二级要学的函数有哪些,计算机二级ms office中excel中必考函数有哪些?
  20. clCreateBuffer中cl_mem_flags参数解释

热门文章

  1. videojs 播放 hls 流视频 自动播放(autoplay + muted)
  2. 量化实战之银行零售资产分池
  3. 分布式事务解决方案(总览)
  4. abaqus切削为什么没有切屑_Abaqus切削仿真常见问题及其解决个人总结
  5. FM,FMM,deepFFM模型总结,深度排序模型
  6. grid布局看这一篇就够了
  7. 常见的比较二进制工具有哪些
  8. Arduino温湿度监测与股票涨跌提醒
  9. SSM在线车队货车管理系统
  10. 红旗Linux的特点和应用范围,三大特性!红旗Linux Desktop 7体验