商人過河問題_6人過河問題_3商人3隨從過河問題_python求全部解

"""
三個商人帶了三個隨從準備過河,目前只有一條空船(至少需要一人划船),並且最大承重兩人,
這時隨從商議在河的任意一岸只要商人的數量少於隨從的數量,那隨從就會殺人越貨,
請問商人要怎麼安全過河?
"""

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()

結果:

[['隨從', '隨從'], ['隨從'], ['隨從', '隨從'], ['隨從'], ['商人', '商人'], ['商人', '隨從'], ['商人', '商人'], ['隨從'], ['隨從', '隨從'], ['商人'], ['商人', '隨從']]
[['商人', '隨從'], ['商人'], ['隨從', '隨從'], ['隨從'], ['商人', '商人'], ['商人', '隨從'], ['商人', '商人'], ['隨從'], ['隨從', '隨從'], ['商人'], ['商人', '隨從']]
[['隨從', '隨從'], ['隨從'], ['隨從', '隨從'], ['隨從'], ['商人', '商人'], ['商人', '隨從'], ['商人', '商人'], ['隨從'], ['隨從', '隨從'], ['隨從'], ['隨從', '隨從']]
[['商人', '隨從'], ['商人'], ['隨從', '隨從'], ['隨從'], ['商人', '商人'], ['商人', '隨從'], ['商人', '商人'], ['隨從'], ['隨從', '隨從'], ['隨從'], ['隨從', '隨從']]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章