python 回溯法 子集树模板 系列 —— 19、野人与传教士问题

简介:

问题

在河的左岸有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)

效果图

709432-20170625094824991-1555180912.jpg

解的解释,从上往下看:
709432-20170625100140913-304725280.jpg

一个结论

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

本文转自罗兵博客园博客,原文链接:http://www.cnblogs.com/hhh5460/p/7076172.html ,如需转载请自行联系原作者
相关文章
|
2月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
39 4
|
10天前
|
存储 大数据 索引
解锁Python隐藏技能:构建高效后缀树Suffix Tree,处理大数据游刃有余!
通过构建高效的后缀树,Python程序在处理大规模字符串数据时能够游刃有余,显著提升性能和效率。无论是学术研究还是工业应用,Suffix Tree都是不可或缺的强大工具。
24 6
|
7天前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
25 2
|
12天前
|
存储 算法 数据挖掘
高效文本处理新纪元:Python后缀树Suffix Tree,让数据分析更智能!
在大数据时代,高效处理和分析文本信息成为关键挑战。后缀树作为一种高性能的数据结构,通过压缩存储字符串的所有后缀,实现了高效的字符串搜索、最长公共前缀查询等功能,成为文本处理的强大工具。本文探讨Python中后缀树的应用,展示其在文本搜索、重复内容检测、最长公共子串查找、文本压缩及智能推荐系统的潜力,引领数据分析迈入新纪元。虽然Python标准库未直接提供后缀树,但通过第三方库或自定义实现,可轻松利用其强大功能。掌握后缀树,即掌握开启文本数据宝藏的钥匙。
34 5
|
8天前
|
存储 开发者 Python
从理论到实践:Python中Trie树与Suffix Tree的完美结合,开启编程新篇章!
在编程领域,高效的数据结构对于解决问题至关重要。本文通过一个案例分析,介绍如何在Python中结合使用Trie树(前缀树)和Suffix Tree(后缀树)。案例聚焦于开发具备高效拼写检查和文本相似度检测功能的文本编辑器。首先,通过构建Trie树快速检查单词是否存在;接着,利用Suffix Tree检测文本相似度。尽管Python标准库未直接提供Suffix Tree,但可通过第三方库或自定义实现。本文展示了高级数据结构在实际应用中的强大功能,并强调了理论与实践相结合的重要性。
20 1
|
8天前
|
存储 算法 Python
逆袭之路:掌握Python字典树Trie与后缀树,成为技术圈的耀眼新星!
在编程的征途上,每个人都渴望成为那个能够独当一面、解决复杂问题的技术高手。而掌握高级数据结构,如字典树(Trie)与后缀树(Suffix Tree),无疑是你逆袭路上的重要一步。这些数据结构不仅能够提升你的编码技能,还能让你在解决特定问题时游刃有余,从而在技术圈中脱颖而出,成为那颗耀眼的新星。
18 1
|
9天前
|
存储 算法 搜索推荐
Python进阶必备:字典树Trie与后缀树Suffix Array,效率提升的神器!
在Python编程中,掌握高效的数据结构对于提升程序性能至关重要。本文将深入探讨两种强大的字符串处理数据结构——字典树(Trie)与后缀数组(Suffix Array)。字典树,又称前缀树,适用于自动补全和拼写检查等功能。例如,在文本编辑器中实现自动补全时,字典树能够即时提供单词补全选项。后缀数组则用于存储字符串的所有后缀并按字典序排序,结合最长公共前缀(LCP)数组,可以高效解决许多字符串问题,如查找最长重复子串等。通过实际案例,我们将展示这两种数据结构的强大功能,帮助你在Python编程中更进一步。
26 2
|
12天前
|
存储 算法 索引
从菜鸟到大神:一文带你彻底搞懂Python中的后缀树Suffix Tree奥秘!
在Python编程中,后缀树是一种高效的数据结构,特别适用于处理复杂的字符串问题,如搜索、最长公共前缀查询及最长重复子串查找等。本文通过问答形式介绍后缀树的基本概念、重要性及其实现方法。后缀树能显著提高字符串处理效率,将传统方法的时间复杂度从O(nm)降至接近O(m)。尽管其构建过程较复杂,但通过手动编写代码或使用第三方库,我们可以在Python中实现这一强大工具。后缀树的应用广泛,涵盖字符串搜索、压缩、生物信息学等多个领域,学习它不仅能帮助解决实际问题,更能提升算法思维和数据结构设计能力。
28 1
|
2月前
|
前端开发 JavaScript 数据库
python Django教程 之模板渲染、循环、条件判断、常用的标签、过滤器
python Django教程 之模板渲染、循环、条件判断、常用的标签、过滤器
|
2月前
|
Python
Python笔下那些神奇的树
Python笔下那些神奇的树
下一篇
无影云桌面