DLS 深度受限搜索 狼羊 过河 问题 python 实现

本文介绍了使用深度受限搜索(DLS)算法解决经典的狼羊过河问题。通过设定操作方法(action)并在递归过程中检查每个节点的可行性和深度限制,确保找到符合条件的解决方案。此外,还提供了代码示例来展示如何输出所有可能的解决方案路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深度受限搜索(DLS)简单地说就是深度有限搜索(DFS)+深度限制(limit)

 

DLS伪代码

 

实例:狼羊 过河 问题

 

3只羊和3头狼在河岸A,想要过河抵达河岸B。它们只有一艘船并且船上必须有1-2只生物。当

任意一边的狼的数量大于羊时,羊会被吃光(fail)。初始状态为(3,3,1,0,0,0),意为3头羊

,3头狼和一艘船在河岸A,而河岸B没有羊,没有狼,也没有船。算法程序要达成的目标是(

0,0,0,3,3,1),意为3头羊,3头狼和一艘船都从河岸A抵达了河岸B。请用深度受限搜索(

Depth-Limited-Search)完成这份python程序,受限深度为15。

思路:

action是所有的操作方法,递归的时候在每个节点都要判断从它延伸的其他以下节点是否符合所需要的操作。然后再加上递归的深度限制,就可以解决。

代码1:

# -*- coding: utf-8 -*-
# Python版本:3.6



# 已探索集合
_explored = []

action = [[0, -1, 0], [0, -2, 0], [-1, 0, 0], [-2, 0, 0], [-1, -1, 0], [0, 1, 1], [0, 2, 1], [1, 0, 1], [2, 0, 1], [1, 1, 1]]

# 节点数据结构
class Node:
    def __init__(self, state, parent, action):
        self.state = state
        self.parent = parent
        self.action = action





def main():
    global _explored

    src_state=[3,3,1,0,0,0]
    dst_state=[0,0,0,3,3,1]
    limit=15

    result = depth_limited_search(src_state, dst_state, limit)
    if result == "failure" or result == "cutoff":
        print('from src_state: %s to dst_state %s search failure' % (src_state, dst_state))
    else:
        print('from src_state: %s to dst_state %s search success' % (src_state, dst_state))
        path = []
        while True:
            path.append(result.state)
            if result.parent is None:
                break
            result = result.parent
        size = len(path)
        for i in range(size):
            if i < size - 1:
                print('%s->' % path.pop(), end='')
            else:
                print(path.pop())


def depth_limited_search(src_state, dst_state, limit):
    global _explored
    _explored = []
    node = Node(src_state, None, None)
    return recursive_dls(node, dst_state, limit)


def recursive_dls(node, dst_state, limit):
    """
        :param node:
        :param dst_state:
        :param limit:
        :return: "failure":失败."cutoff":被截至.node:成功
        """
    global _explored

    if node.parent is not None:
        print('node state:%s parent state:%s' % (node.state, node.parent.state))
    else:
        print('node state:%s parent state:%s' % (node.state, None))
    _explored.append(node.state)

    # 目标测试
    if node.state == dst_state:
        print('this node is goal!')
        return node
    elif limit == 0:
        print('this node is cutoff!')
        return "cutoff"
    else:
        cutoff_occurred = False

        # 遍历子节点
        for state in action:
            if node.state[5] == state[2] and (node.state[1] + state[1]) >= 0 and (
                    node.state[1] + state[1]) <= 3 \
                    and (node.state[0] + state[0]) >= 0 and (node.state[0] + state[0]) <= 3:
                left_sheep = node.state[0] + state[0]
                left_wolf = node.state[1] + state[1]
                right_sheep = node.state[3] - state[0]
                right_wolf = node.state[4] - state[1]
                next_state = list(node.state)

                if (left_sheep == 0 or (left_sheep > 0 and left_sheep >= left_wolf)) and \
                        (right_sheep == 0 or (right_sheep > 0 and right_sheep >= right_wolf)):
                    next_state[0] = left_sheep
                    next_state[1] = left_wolf
                    next_state[2] = int(node.state[5])
                    next_state[3] = right_sheep
                    next_state[4] = right_wolf
                    next_state[5] = int(not (node.state[5]))

                    child = Node(next_state, node, 'do')
                    # 过滤已探索的点
                    if child.state in _explored:
                        continue
                    print('child node:state:%s ' % (child.state ))
                    # 递归的方法,把当前child返回,并且limit-1
                    result = recursive_dls(child, dst_state, limit - 1)
                    if result == "cutoff":
                        cutoff_occurred = True
                        print('search failure, child state: %s parent state: %s limit cutoff' %
                              (child.state, child.parent.state))
                    elif result != "failure":
                        print('search success')
                        print("At the currnet" ,node.state,"you will take the action",state,"and then,your new state is ",child.state)
                        return result
        if cutoff_occurred:
            return "cutoff"
        else:
            return "failure"


if __name__ == '__main__':
    main()

拓展:输出所有的路径

代码2:

# -*- coding: utf-8 -*-
from collections import deque
# 羊 狼 船 羊 狼 船
initial_state = [3, 3, 1, 0, 0, 0]  # 初始状态
final_state = [0, 0, 0,3, 3, 1]  # 最终状态

action = [[0, -1, 0], [0, -2, 0], [-1, 0, 0], [-2, 0, 0], [-1, -1, 0], [0, 1, 1], [0, 2, 1], [1, 0, 1], [2, 0, 1],
          [1, 1, 1]]

# 利用python的deque队列记录状态转移情况,初始化时加入初始状态。deque是可以从头尾插入和删除的队列,在不指定大小时,为一个无边界的队列
record = deque()
record.append(initial_state)


def next_state_lawful(current_state):

    # 下一个动作判定
    next_action = []
    for state in action:
        #current_state[5] == state[2]是判断右侧的船和action的船,相同就可以用这个action
        #后面的判断狼和羊经过action的操作之后是否是大于0 小于3的
        if current_state[5] == state[2] and (current_state[1] + state[1]) >= 0 and (current_state[1] + state[1]) <= 3 \
                and (current_state[0] + state[0]) >= 0 and (current_state[0] + state[0]) <= 3:
            next_action.append(state)

    # 下一个状态
    for state in next_action:
        left_sheep = current_state[0] + state[0]
        left_wolf = current_state[1] + state[1]
        right_sheep = current_state[3] - state[0]
        right_wolf = current_state[4] - state[1]
        next_state = list(current_state)

        if (left_sheep == 0 or (left_sheep > 0 and left_sheep >= left_wolf)) and \
                (right_sheep == 0 or (right_sheep > 0 and right_sheep >= right_wolf)):
            next_state[0] = left_sheep
            next_state[1] = left_wolf
            next_state[2] = int(current_state[5])
            next_state[3] = right_sheep
            next_state[4] = right_wolf
            next_state[5] = int(not (current_state[5]))
            yield next_state

        # 记录调试的变量:num表示总共实现方法数,record_list记录所有实现路径


num = 0
record_list = []


def searchResult(record,limit):
    if limit==0:
        return
    global num, record_list
    # 由record的末尾元素得到当前状态
    current_state = record[-1]
    # 得到关于当前状态的下一状态的可迭代生成器,供下一步循环使用
    next_state = next_state_lawful(current_state)

    # 遍历所有可能的下一状态
    for state in next_state:
        if state not in record:
            # 保证当前状态没在以前出现过。如果状态已经出现还进行搜索就会形成状态环路,陷入死循环。
            record.append(state)
            # 添加新的状态到列表中
            if state == final_state:
                print(record)
                # 打印出可行方案
                # record_list.append(record)这样使用错误,导致加入列表的是record的引用,应该使用下面的式子来进行深复制,得到一个新的队列再加入列表。
                record_list.append(deque(record))
                num += 1
            else:
                # 递归搜索
                searchResult(record,limit-1)

            # 去除当前循环中添加的状态,进入下一个循环,关键步,第一次实现的时候遗漏了
            record.pop()
searchResult(record,15)
print("总共实现方式的种类数目:", num)
print("实现方式的最少步骤为:%d 步" % (min([len(i) for i in record_list])-1))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值