博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python 回溯法 子集树模板 系列 —— 19、野人与传教士问题
阅读量:5890 次
发布时间:2019-06-19

本文共 2112 字,大约阅读时间需要 7 分钟。

问题

在河的左岸有N个传教士、N个野人和一条船,传教士们想用这条船把所有人都运过河去,但有以下条件限制:

(1)修道士和野人都会划船,但船每次最多只能运M个人;

(2)在任何岸边以及船上,野人数目都不能超过修道士,否则修道士会被野人吃掉。

假定野人会服从任何一种过河安排,请规划出一个确保修道士安全过河的计划。

分析

百度一下,网上全是用左岸的传教士和野人人数以及船的位置这样一个三元组作为状态,进行考虑,千篇一律。

我换了一种考虑,只考虑船的状态。

船的状态:(x, y) x表示船上x个传教士,y表示船上y个野人,其中 |x|∈[0, m], |y|∈[0, m], 0<|x|+|y|<=m, x*y>=0, |x|>=|y|

船从左到右时,x,y取非负数。船从右到左时,x,y取非正数

解的编码:[(x0,y0), (x1,y1), ..., (xp,yp)] 其中x0+x1+...+xp=N, y0+y1+...+yp=N

解的长度不固定,但一定为奇数

开始时左岸(N, N), 右岸(0, 0)。最终时左岸(0, 0), 右岸(N, N)

由于船的合法状态是动态的、二维的。因此,使用一个函数get_states()来专门生成其状态空间,使得主程序更加清晰。

代码

n = 3  # n个传教士、n个野人m = 2  # 船能载m人x = [] # 一个解,就是船的一系列状态X = [] # 一组解is_found = False # 全局终止标志# 计算船的合法状态空间(二维)def get_states(k): # 船准备跑第k趟    global n, m, x        if k%2==0:  # 从左到右,只考虑原左岸人数        s1, s2 = n - sum(s[0] for s in x), n - sum(s[1] for s in x)    else:       # 从右到左,只考虑原右岸人数(将船的历史状态累加可得!!!)        s1, s2 = sum(s[0] for s in x), sum(s[1] for s in x)        for i in range(s1 + 1):        for j in range(s2 + 1):            if 0 < i+j <= m and (i*j == 0 or i >= j):                yield [(-i,-j), (i,j)][k%2==0]   # 生成船的合法状态# 冲突检测def conflict(k): # 船开始跑第k趟    global n, m, x        # 若船上载的人与上一趟一样(会陷入死循环!!!!)    if k > 0 and x[-1][0] == -x[-2][0] and x[-1][1] == -x[-2][1]:        return True            # 任何时候,船上传教士人数少于野人,或者无人,或者超载(计算船的合法状态空间时已经考虑到了。)    #if 0 < abs(x[-1][0]) < abs(x[-1][1]) or x[-1] == (0, 0) or abs(sum(x[-1])) > m:    #    return True        # 任何时候,左岸传教士人数少于野人    if 0 < n - sum(s[0] for s in x) < n - sum(s[1] for s in x):        return True        # 任何时候,右岸传教士人数少于野人    if 0 < sum(s[0] for s in x) < sum(s[1] for s in x):        return True        return False # 无冲突            # 回溯法def backtrack(k): # 船准备跑第k趟    global n, m, x, is_found        if is_found: return  # 终止所有递归        if n - sum(s[0] for s in x) == 0 and n - sum(s[1] for s in x) == 0: # 左岸人数全为0        print(x)        is_found = True    else:        for state in get_states(k): # 遍历船的合法状态空间            x.append(state)            if not conflict(k):                backtrack(k+1) # 深度优先            x.pop()   # 回溯# 测试backtrack(0)

效果图

img_d61dd7bbd505e09713c4c0f0f5631f3b.jpg

解的解释,从上往下看:

img_118371eccde25ce7027707255f85f42e.jpg

一个结论

貌似只有满足m = n-1,此问题才有解

转载地址:http://inbsx.baihongyu.com/

你可能感兴趣的文章
洛谷 1365 WJMZBMR打osu! / Easy
查看>>
删除UINavigationItem上的BarButtonItem
查看>>
数据分析相关模块
查看>>
Python数据结构1-----基本数据结构和collections系列
查看>>
SQL Denali-FileTable
查看>>
C# 图像处理:复制屏幕到内存中,拷屏操作
查看>>
PHP微信支付流程
查看>>
linux下单节点oracle数据库间ogg搭建
查看>>
swift三方库
查看>>
杭州之行
查看>>
oracle ORA-00917: missing comma 是因为少逗号
查看>>
策略模式简介
查看>>
UIViewController中loadView的用法(应当注意的几点)
查看>>
POJ NOI0105-42 画矩形
查看>>
Java 数组在内存中的结构
查看>>
《关爱码农成长计划》第一期报告
查看>>
entity framework 6 通用数据类
查看>>
读取FTP上的excel文件,并写入数据库
查看>>
vs2008快捷键极其技巧 转载
查看>>
window 7上安装Visual Studio 2017失败的解决方法
查看>>