关于#python#的问题:如果两侧河岸上的狮子数量大于羚羊数量

写一个程序来解决这样一个问题:3 只羚羊和3 只狮子准备乘船过河,河边有一艘能容纳2 只动物的小船。但是,如果两侧河岸上的狮子数量大于羚羊数量,羚羊就会被吃掉。
找到运送办法,使得所有动物都能安全渡河。
每个循环每个分支每个变量可以有注释

代码的输出结果含义是小船每次一来一回载的动物

img

from collections import Counter
from random import sample, randint
class Solution:
    """解决问题的方案类"""

    def __init__(self):
        """初始化属性"""
        self.left = ['羚羊'] * 3 + ['狮子'] * 3  # 后面用到了Counter,所以这里可以用字符串表示,不用0,1表示,更直观一点
        self.left_checkpoint = []  # 左边的存档,用于试错后恢复
        self.right = []
        self.right_checkpoint = []
        self.result = [[]]  # 结果,给个初始值是为了避免out of index的情况,取结果的时候切片即可
        self.result_checkpoint = []
        self.r_direction = True  # True为右,False为左

    def go(self):
        """渡河"""
        if self.r_direction:  # 向右渡河
            boat = sample(self.left, 2)
            for i in boat:
                self.left.remove(i)
                self.right.append(i)
        else:  # 向左渡河
            if len(self.right) > 1:  # 这里判断是为了避免sample取的时候越界(从1个里面取2个)
                boat = sample(self.right, randint(1, 2))
            else:
                boat = sample(self.right, 1)
            for i in boat:
                self.right.remove(i)
                self.left.append(i)
        return boat

    def judge(self):
        """判断"""
        if self.left and self.right:
            left_counter = Counter(self.left)
            right_counter = Counter(self.right)
            if (left_counter['羚羊'] and left_counter['羚羊'] < left_counter['狮子']) or \
                    (right_counter['羚羊'] and right_counter['羚羊'] < right_counter['狮子']):
                return False
        return True

    def checkpoint(self):
        """检查点"""
        self.left_checkpoint, self.right_checkpoint, self.result_checkpoint = \
            self.left.copy(), self.right.copy(), self.result.copy()

    def reset(self):
        """读档"""
        self.left, self.right, self.result = \
            self.left_checkpoint.copy(), self.right_checkpoint.copy(), self.result_checkpoint.copy()

    def get_result(self):
        """模拟渡河过程,获取结果"""
        while len(self.right) < 6:
            self.checkpoint()  # 存档
            boat = self.go()  # 渡河
            boat.sort()
            if self.judge() and boat != self.result[-1]:  # 这里判断是为了避免相同的人来回的情况,以求尽可能少的解
                self.r_direction = not self.r_direction  # 调转船头
                self.result.append(boat)
            else:
                self.reset()  # 读档
        return self.result[1:]


def main():
    """主函数"""

    repeat = 10000  # 重复执行次数
    result_set = set()  # 解的集合
    solution = Solution()

    for _ in range(repeat):
        result = solution.get_result()
        result_set.add(str(result))
        solution.__init__()

    print(f'经{repeat}次执行,共得到{len(result_set)}种不同的结果,结果如下:', end='\n\n')
    for result in result_set:

        print(result)
if __name__ == '__main__':
    main()

我知道答案,先运一只狮子,再运一只羊,再运两只羊,再运两只狮子,安全渡河,代码不会实现。
狮子和羊如果能一起运
分三次运一只狮子一只羊
python代码不会实现。
能否用java
有用请采纳

实现代码, 参考: https://blog.csdn.net/ggjkd/article/details/119086844:

from pythonds.graphs import Graph
from pythonds.basic import Queue
def solution():
    '''
    3只羚羊和3只狮子过河问题:
        1艘船只能容纳2只动物
        当河岸上狮子数大于羚羊数,羚羊就会被吃掉
        找到运输方法,让所有动物都过河
    '''

    # 定义合法的运输操作(i, j) , 例如(1, 0)表示运送羚羊1只,狮子0只
    opt = [(1, 0), (0, 1), (1, 1), (2, 0), (0, 2)]

    # 定义状态state(m, n, k), m表示羚羊数,n表示狮子数,k表示船在此岸还是彼岸
    # stateA 表示A岸(此岸)的状态;stateB 表示B岸(彼岸)的状态;

    # 初始状态
    stateA = (3, 3, 1)
    stateB = (0, 0, 0)

    # BFS搜索
    mygraph = Graph()
    myqueue = Queue()
    myqueue.enqueue((stateA, stateB))
    sequence = []  # 剪枝记录(最后发现,有效状态只有15种)
    sequence.append((stateA))
    while True:
        stateA, stateB = myqueue.dequeue()

        if stateA == (0, 0, 0):
            break
        for o in opt:
            # 一次从某岸到另一岸的运输
            if stateA[2] == 1:
                stateA_ = (stateA[0] - o[0], stateA[1] - o[1], stateA[2] - 1)
                stateB_ = (stateB[0] + o[0], stateB[1] + o[1], stateB[2] + 1)
            else:
                stateB_ = (stateB[0] - o[0], stateB[1] - o[1], stateB[2] - 1)
                stateA_ = (stateA[0] + o[0], stateA[1] + o[1], stateA[2] + 1)

            # 运输后
            if stateA_[0] and stateA_[0] < stateA_[1]:  # 此岸在有羊的情况下,如果狼大于羊,则吃掉
                continue
            elif stateB_[0] and stateB_[0] < stateB_[1]:  # 彼岸在有羊的情况下,如果狼大于羊,则吃掉
                continue
            elif stateA_[0] < 0 or stateA_[0] > 3 or stateA_[1] < 0 or stateA_[1] > 3:  # 边界
                continue
            else:
                # 剪枝
                if stateA_ in sequence:
                    continue
                else:
                    sequence.append(stateA_)
                    myqueue.enqueue((stateA_, stateB_))
                    mygraph.addEdge(stateA, stateA_, o)

    return mygraph, sequence
if __name__ == '__main__':
    g, sq = solution()

    # 建立父子关系
    for v_n in sq:
        v = g.getVertex(v_n)

        for nbr in v.getConnections():
            if nbr.getColor() == 'white':
                nbr.setPred(v)
                nbr.setColor('gray')
        v.setColor('black')
    target = g.getVertex(sq[-1])

    # 回溯,显示决策路径
    while target.getPred():
        predv = target.getPred()
        print(target.id, '<--', predv.getWeight(target), '--', predv.id)
        target = predv




详细的代码注释和解释如下,望采纳,有问题随时交流.

  • 下面代码中,我们使用了一个 while 循环,每次检查是否可以安全地运送动物。如果可以,就将一只狮子和一头羚羊从一侧运送到另一侧。如果不能,就输出错误信息。循环继续执行,直到所有动物都在河的右侧。

  • 我们假设船只能运送一只狮子和一头羚羊。如果想要运送其他数量的动物,可以更改代码中的数字即可。

# 初始化河两侧狮子和羚羊的数量
lions_left = 3
antelopes_left = 3
lions_right = 0
antelopes_right = 0

# 跟踪船的位置
boat_at_left = True

# 循环,直到所有动物都在河的右侧
while lions_right + antelopes_right < 6:
    # 检查是否可以安全地运送动物
    if boat_at_left:
        if lions_left > antelopes_left:
            print("无法安全地运送动物!")
        else:
            # 从左侧运送一只狮子和一头羚羊到右侧
            lions_left -= 1
            antelopes_left -= 1
            lions_right += 1
            antelopes_right += 1
            boat_at_left = False
    else:
        if lions_right > antelopes_right:
            print("无法安全地运送动物!")
        else:
            # 从右侧运送一只狮子和一头羚羊到左侧
            lions_left += 1
            antelopes_left += 1
            lions_right -= 1
            antelopes_right -= 1
            boat_at_left = True

# 所有动物都在河的右侧
print("所有动物都在河的右侧!")

思路:
1)题目意思是,原来岸边有3狮3羊,最后要安全渡河,变成0狮0羊,那么状态必有狮子数和羊数;
2)什么导致状态发生变化,是用船运送,那船在此岸还是彼岸?一开始船肯定在此岸,最后运输完成后,船必然是在彼岸,故船在哪个岸应该也要作为状态;
于是,定义状态state:
state = (m, n, k)
m: 羊数,0 <= m <= 3
n: 狮子数,0 <= n <= 3
k: 船在哪个岸,k = {0, 1}, 1表示在A岸(也就是此岸);0表示在B岸(也就是在彼岸)
那么,最终就是搜索A岸从(3,3,1)—> (0,0,0)
注:理论上可能的状态一共有32种,即 4 * 4 * 2 = 32
根据题意,船运输的羊和狮子的数量满足:
1)总数不超过2:m + n <= 2
2)羊数不小于狮子数:m >= n
那么,策略一共有以下5种:
(1,0), (0,1), (1,1), (2,0), (0,2)
例如,(1,0)表示运输羊1只狮子0只
参考代码:

from pythonds.graphs import Graph
from pythonds.basic import Queue
def solution():
    '''
    3只羚羊和3只狮子过河问题:
        1艘船只能容纳2只动物
        当河岸上狮子数大于羚羊数,羚羊就会被吃掉
        找到运输方法,让所有动物都过河
    '''

    # 定义合法的运输操作(i, j) , 例如(1, 0)表示运送羚羊1只,狮子0只
    opt = [(1, 0), (0, 1), (1, 1), (2, 0), (0, 2)]

    # 定义状态state(m, n, k), m表示羚羊数,n表示狮子数,k表示船在此岸还是彼岸
    # stateA 表示A岸(此岸)的状态;stateB 表示B岸(彼岸)的状态;

    # 初始状态
    stateA = (3, 3, 1)
    stateB = (0, 0, 0)

    # BFS搜索
    mygraph = Graph()
    myqueue = Queue()
    myqueue.enqueue((stateA, stateB))
    sequence = []  # 剪枝记录(最后发现,有效状态只有15种)
    sequence.append((stateA))
    while True:
        stateA, stateB = myqueue.dequeue()

        if stateA == (0, 0, 0):
            break
        for o in opt:
            # 一次从某岸到另一岸的运输
            if stateA[2] == 1:
                stateA_ = (stateA[0] - o[0], stateA[1] - o[1], stateA[2] - 1)
                stateB_ = (stateB[0] + o[0], stateB[1] + o[1], stateB[2] + 1)
            else:
                stateB_ = (stateB[0] - o[0], stateB[1] - o[1], stateB[2] - 1)
                stateA_ = (stateA[0] + o[0], stateA[1] + o[1], stateA[2] + 1)

            # 运输后
            if stateA_[0] and stateA_[0] < stateA_[1]:  # 此岸在有羊的情况下,如果狼大于羊,则吃掉
                continue
            elif stateB_[0] and stateB_[0] < stateB_[1]:  # 彼岸在有羊的情况下,如果狼大于羊,则吃掉
                continue
            elif stateA_[0] < 0 or stateA_[0] > 3 or stateA_[1] < 0 or stateA_[1] > 3:  # 边界
                continue
            else:
                # 剪枝
                if stateA_ in sequence:
                    continue
                else:
                    sequence.append(stateA_)
                    myqueue.enqueue((stateA_, stateB_))
                    mygraph.addEdge(stateA, stateA_, o)

    return mygraph, sequence
if __name__ == '__main__':
    g, sq = solution()

    # 建立父子关系
    for v_n in sq:
        v = g.getVertex(v_n)

        for nbr in v.getConnections():
            if nbr.getColor() == 'white':
                nbr.setPred(v)
                nbr.setColor('gray')
        v.setColor('black')
    target = g.getVertex(sq[-1])

    # 回溯,显示决策路径
    while target.getPred():
        predv = target.getPred()
        print(target.id, '<--', predv.getWeight(target), '--', predv.id)
        target = predv

考虑因素:
1、小船载动物到岸边不下船算不算这个动物到岸
2、小船可不可以往回运动物
3、动物上下船有没有先后顺序(是否存在先上了一只羊,导致岸边的狮子数量大于羊)
4、求最优解还是有最大步骤限制