传教士与野人过河问题

news2024/11/15 15:29:31

代码模块参考文章:传教士与野人过河问题(numpy、pandas)_python过河问题_醉蕤的博客-CSDN博客

问题描述

一般的传教士和野人问题(Missionaries and  Cannibals):有N个传教士和C个野人来到河边准 备渡河。河岸有一条船,每次至多可供K人乘渡。 问传教士为了安全起见,应如何规划摆渡方案,使 得任何时刻,在河的两岸以及船上的野人数目总是 不超过传教士的数目,但允许在河的某一岸只有野 人而没有传教士。

这里讨论基于N=3,C=3,k=2

状态表示:(m,w,B);初始状态: (3, 3, 1);目标状态: (0,0,0)

启发性规则

操作符(产生式规则)
左岸往右岸运载产生式
L10  if(M,W,1) then (M-1,W,0)     (左往右运1传教士)
L01  if(M,W,1) then (M,W-1,0)     (左往右运1野人)
L11  if(M,W,1) then (M-1,W-1,0)  (左往右运1传教士和1野人)
L20  if(M,W,1) then (M-2,W,0)     (左往右运2传教士)
L02  if(M,W,1) then (M,W-2,0)     (左往右运2野人)

右岸往左岸运载产生式
R10  if(M,W,0) then (M+1,W,1)    (右往左运1传教士)
R01  if(M,W,0) then (M,W+1,1)    (右往左运1野人)
R11  if(M,W,0) then (M+1,W+1,1) (右往左运1传教士和1野人)
R20  if(M,W,0) then (M+2,W,1)    (右往左运2传教士)
R02  if(M,W,0) then (M,W+2,1)    (右往左运2野人)

路径方案展示

总共有四种解决方案

实现代码(含具体解释)

import numpy as np

M = int(input("请输入传教士的数量:"))  # 传教士数量
C = int(input("请输入野人的数量:"))  # 野人数量
K = int(input("请输入船的最大容量:"))  # 船的最大容量

child = []  # child:用于存储所有扩展节点
open_list = []  # open list
closed_list = []  # closed list


class State:
    def __init__(self, m, c, b):
        self.m = m  # 左岸传教士的数量
        self.c = c  # 左岸野人的数量
        self.b = b  # b为1时船在左岸;b为0时船在右岸
        self.g = 0  # 该结点所在的层级
        self.f = 0  # 该结点的启发性层度f = g + h
        # father这个属性是State
        self.father = None
        self.node = np.array([m, c, b])


init = State(M, C, 1)  # 初始节点
goal = State(0, 0, 0)  # 目标节点


# 判断状态是否合法
def safe(s):
    # 下面是要排除的条件,并且给出了为什么要排除的理由
    # s.m > M or s.m < 0 题目要求传教士的数量
    # s.c < 0 or (s.m != 0 and s.m < s.c) 有教士时,野兽的数量不能大于教士
    # s.m != M and M - s.m < C - s.c 对岸不全是怪兽时,对岸上的怪兽不能大于对岸上的教士
    if s.m > M or s.m < 0 or s.c > C or s.c < 0 or (s.m != 0 and s.m < s.c) or (s.m != M and M - s.m < C - s.c):
        return False
    else:
        # 状态合法
        return True


# 启发函数
def h(s):
    # 传教士数量+野人数量-船的位置与船的最大容量的乘积
    # 我们希望这个值越越小越好
    # 他的含义:岸上传教士数量+岸上野人数量之后
    # 如果这船在对岸(这是我们希望的,说明顺利渡河),于是我们就减上K*s.b
    # 如果船不在对岸,这不是我们希望的,所以不进行任何减数的操作(K=0)
    return s.m + s.c - K * s.b


# 判断两个状态是否相同
def equal(a, b):
    if np.array_equal(a.node, b.node):
        return 1, b
    else:
        return 0, b


# 判断当前状态是否与父状态一致
# new 是新结点,s是它的父节点
def back(new, s):
    if s.father is None:
        return False
    c = b = s.father
    while True:
        # 不断回溯,去找他的父结点是否与new结点相同
        a, c = equal(new, b)
        if a:
            return True
        b = c.father
        if b is None:
            # 此时找到的b是根结点,停止搜索
            return False


# 根据f值对open_list进行排序
def open_sort(l):
    l.sort(key=lambda x: x.f)


# 在open_list和closed_list中查找具有相同MCB属性的节点
def in_list(new, l):
    for item in l:
        if np.array_equal(new.node, item.node):
            return True, item
    return False, None


# A*算法
def A_star(s):
    A = []
    global open_list, closed_list
    open_list = [s]
    closed_list = []

    while True:  # open_list不为空
        for i in open_list:
            if np.array_equal(i.node, goal.node):  # 判断是否为目标节点
                A.append(i)
                open_list.remove(i)
        if not open_list:
            break
        get = open_list[0]
        open_list.remove(get)  # 从open_list中移除get节点
        closed_list.append(get)  # 将get节点加入closed_list

        # 获取get的子节点并考虑是否将其加入open_list
        for i in range(M + 1):  # 船上传教士数量
            for j in range(C + 1):  # 船上野人数量
                # 船上人数非法: 1:船上无人或者2:船上的人大于规定的载客数或者3:船上有教士并且野怪的数量大于教士
                if i + j == 0 or i + j > K or (i != 0 and i < j):
                    continue

                # 找到满足要求的相对于刚遍历完的结点get的下一个状态
                if get.b == 1:  # 当前船在左岸,下一个状态船在右岸
                    new = State(get.m - i, get.c - j, 0)
                    child.append(new)
                else:  # 当前船在右岸,下一个状态船在左岸
                    new = State(get.m + i, get.c + j, 1)
                    child.append(new)

                # safe(new)判断是否非法
                # back(new, get)这个相对于get结点的孩子回到父状态? TODO
                if not safe(new) or back(new, get):  # 状态非法或已经回到父状态
                    child.pop()
                else:
                    # 定义它的上一个状态的结点
                    new.father = get
                    # 孩子结点层级加1
                    new.g = get.g + 1
                    # 父亲的结点层级+父亲的启发性层度
                    new.f = get.g + h(get)
                    open_list.append(new)
                    open_sort(open_list)
    return A


# 递归打印路径
def print_path(f):
    if f is None:
        return
    # 先递归打印父结点的,再打印自己的结点
    print_path(f.father)
    print(f.node)
    # print(f.f)


if __name__ == '__main__':
    print('传教士数量:%d, 野人数量:%d, 船的最大容量:%d' % (M, C, K))
    final = A_star(init)
    print("共有%d种方案" % len(final))
    if final:
        c = 1
        for i in final:
            print('第%d个方案如下' % c)
            print_path(i)
            c += 1
    else:
        print('没有找到解决方案!')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1272389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

键入网址到网页显示,期间发生了什么?(计算机网络)

浏览器首先会对URL进行解析 下面以http://www.server.com/dir1/file1.html为例 当没有路径名时&#xff0c;就代表访问根目录下事先设置的默认文件&#xff0c;也就是 /index.html 或者 /default.html 对URL进行解析之后&#xff0c;浏览器确定了 Web 服务器和文件名&#x…

多多跨境跑出高质量发展“加速度”,解锁拼多多Q3财报背后的王牌

互联网红利渐趋消退&#xff0c;用户拉新难度加大&#xff0c;这些现象也在表明过去电子商务依靠资本、流量快速增长的发展模式已经成为过去式。由高速发展转为高质量发展&#xff0c;在今天每一个经济体与宏观经济发展态势一般&#xff0c;发展的“质量”价值正在被放大开来。…

一个软件测试练手项目——学生信息管理系统测试,卷起来啊

免费分享一个练手项目&#xff0c;学生信息管理系统&#xff0c;获取方式在文末 1.引言 1.1项目目的 软件测试是为了在软件投入生产性运行之前&#xff0c;尽可能多地发现软件的错误。该项目的目的是给学习软件测试的朋友练手用 1.2 项目背景 随着学校的规模不断扩大&…

学习程序员必知必会的基础算法(收藏)

近年来学习python的程序员愈来愈多&#xff0c;有的同学选择了python培训机构&#xff0c;也有的人觉得自己天赋好选择了自学不管大家怎么去学习&#xff0c;在学习python基础的过程中&#xff0c;肯定离不开的就是基础算法&#xff0c;今天就为大家介绍几大学习中的基础算法。…

1000多页!LeetCode刷题手册分享

这本手册确实是一部令人印象深刻的作品。&#xff08;手册链接在文末&#xff01;&#xff01;&#xff01;&#xff09; 首先&#xff0c;内容充实是这本手册的一大亮点。它涵盖了广泛的算法和数据结构主题&#xff0c;包括数组、链表、树、图、排序算法、动态规划等等。每个…

P28 C++ 对象的生存周期(栈的作用域生存周期)

前言 本期的主题是栈作用域中对象的生存期&#xff0c;通俗来讲&#xff0c;就是讨论对象是如何在栈上生存的。 这章内容整体分为两部分。 第一部分是&#xff0c;你必须理解栈上的东西是如何存在的&#xff0c;这样你才能真正写出能正常工作的代码。第二部分是&#xff0c;一…

什么是AI PC:人工智能电脑?

大家好啊&#xff0c;我是董董灿。 今天在一个群聊里&#xff0c;聊到了关于 AI PC (人工智能电脑)的话题。 之前看到过关于 AI PC 的新闻&#xff0c;说的是联想集团董事长兼CEO杨元庆在一次演讲中提到了 AI PC 的概念&#xff0c;并且绘声绘色的描绘了AI PC 的发展前景。 下…

Windows系列:windows server 2003 - 组策略部署软件

通过组策略为域内用户部署&#xff08;deploy&#xff09;软件&#xff0c;可分为指派&#xff08;assign&#xff09;和发布&#xff08;publish&#xff09;。 软件指派给用户&#xff1a;用户在域内登录后&#xff0c;被“通告 advertised”给用户&#xff0c;此时仅安装了部…

链表_相交链表

//给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 // // 图示两个链表在节点 c1 开始相交&#xff1a; // // // // 题目数据 保证 整个链式结构中不存在环。 // // 注意…

提升技能素养,AMCAP做出合适的决策

近年来&#xff0c;智能配置投资与理财逐渐受到关注并走俏。这是一种简单快捷的智慧化理财方式&#xff0c;通过将个人和家族的闲置资金投入到低风险高流动性的产品中。 国际财富管理投资机构AMCAP集团金融分析师表示&#xff1a;智能配置投资与理财之所以持续走俏&#xff0c…

WebUI工作流插件超越ComfyUI

在AI绘画领域&#xff0c;Stable Diffsion是最受欢迎的&#xff0c;因为它是开源软件。 开源有两大优势&#xff0c;一是免费&#xff0c;二是适合折腾。 大量的开发者、爱好者投入无尽的热情&#xff0c;来推动Stable Diffsion的快速发展。 在图形界面方面&#xff0c;WebU…

Python 进阶(十二):随机数(random 模块)

《Python入门核心技术》专栏总目录・点这里 文章目录 1. 导入random库2. 常用随机数函数2.1 生成随机浮点数2.2 生成随机整数2.3 从序列中随机选择2.4 随机打乱序列3. 设置随机数种子4. 应用实例4.1 游戏开发4.2 数据分析4.3 加密与安全4.4 模拟实验5. 总结大家好,我是水滴~~ …

Linux常用命令——mv命令

文章目录 1. 简介2. 命令格式3. 主要参数4. 常见用法及示例4.1 移动文件4.2 重命名文件4.3 交互式移动文件4.4 强制移动文件4.5 移动多个文件4.6 使用通配符移动文件 5. 注意事项6. 结论 1. 简介 mv 命令在Linux系统中用于移动文件或目录&#xff0c;同时也可以用于重命名文件…

Python使用——发送Get请求,模拟http请求 进行SSH连接服务器

前言 本篇博客是python开发的使用案例博客&#xff0c;结合一些具体的案例进行阐述&#xff0c;本篇博客主要内容是使用Python发送Get请求&#xff0c;模拟http请求&#xff0c;后面可以搞个爬虫出来&#xff0c;另外就是如何使用Python进行SSH连接服务器。 其他相关的博客文…

【代码随想录】算法训练计划37

贪心 1、738. 单调递增的数字 题目&#xff1a; 输入: n 10 输出: 9 思路&#xff1a; func monotoneIncreasingDigits(n int) int {// 贪心&#xff0c;利用字符数组s : strconv.Itoa(n)ss : []byte(s)leng : len(ss)if leng < 1 {return n}for i:leng-1; i>0; i-- …

【MATLAB】异常数据识别

基于分位数的异常点识别 首先&#xff0c;给定了一个原始数据序列x。然后&#xff0c;计算了序列x的上四分位数和下四分位数&#xff0c;并根据这两个值计算了异常点的阈值。上四分位数减去1.5倍的四分位数范围得到异常值下界&#xff0c;下四分位数加上1.5倍的四分位数范围得…

虚拟数据生成_以Python为工具

生成虚拟数据_以Python为工具 生成虚拟数据技术在现实生活中具有多个重要的应用领域。它为数据隐私保护、机器学习算法开发、数据处理和可视化等方面提供了实用且有价值的解决方案。尤其是能满足定制化需求的虚拟数据&#xff0c;在预期的方向上让数据定向随机。 &#x1f339…

下载MySQL JDBC驱动的方法

说明 java代码通过JDBC访问MySQL数据库&#xff0c;需要MySQL JDBC驱动。 例如&#xff0c;下面这段代码&#xff0c;因为找不到JDBC驱动&#xff0c;所以执行会报异常&#xff1a; package com.thb;public class JDBCDemo {public static void main(String[] args) throws …

全网最最全的Jmeter接口测试:jmeter_逻辑控制器_交替控制器Jmeter(22):jmeter_逻辑控制器_交替控制器

交替控制器 该控制器包含的取样器步骤在每次循环中交替执行 交替控制器指每次运行一次时在交替控制器下的采样器只执行一个&#xff1b;如下图&#xff1a; 忽略子控制模块&#xff1a;如果勾选此项,交替控制器将子控制器像单一请求元素一样&#xff0c;一次 只允许一个请求/…

csdn最新最全面的Jmeter接口测试:jmeter_逻辑控制器_循环控制器

循环控制器 循环次数&#xff1a;设置该控制器下的请求的循环执行次数 永远&#xff1a;勾选上的话&#xff0c;会一直循环&#xff0c;即所谓死循环 注意&#xff1a;如果线程组本身已经设置了循环次数的话&#xff0c;那循环控制元件控制的子节点 的循环次数为线程组设置的…