【Python 3】回溯法解九數字問題

問題再現

求一個九位數M,已知M的各位數由不重複的1\sim 9組成,對於m \in \begin{Bmatrix} 2, 3, 4, \cdots , 9 \end{Bmatrix},數M左側的m位數都是m的倍數。


解題思路

左側m位數必須是m的倍數,那麼我們能否使用回溯法:從左側開始,每次向右確定1位數,若從某一位數開始無法找到滿足條件的前m位數,則向左刪除最後一位數並嘗試其他值?這樣,我們可以減少“無腦枚舉”產生的大量無用值,更快地得到結果。


算法示例

def check(prev_nums: list, number: int) -> bool:
    ''' 判斷當前數位是否滿足題目要求 '''

    # 當前數位的數字不能存在於前序數位中
    is_contained = (str(number) not in prev_nums)

    # 前k位數必須能被k整除
    is_zero = (
        (10 * int(''.join(prev_nums)) + number) % len(prev_nums) == 0
    )

    # 同時滿足以上2個條件才爲真
    return (is_contained and is_zero)


def search_num(prev_nums=['0']):
    ''' 遞歸搜索數值 '''

    # 遍歷數字1~9
    for k in range(1, 10):
        # 檢查是否滿足要求
        if check(prev_nums, k):
            # 追加此數值
            prev_nums.append(str(k))

            # 如果已經求出了指定位數且滿足條件的要求
            if len(prev_nums) - 1 == 9:
                # 返回最終的k位數
                return int(''.join(prev_nums))
            else:
                # 否則繼續檢索下一位
                temp = search_num(prev_nums)

                # 如果下一位存在可行數值
                if temp is not None:
                    # 返回下一位的檢索結果
                    return temp

    # 當前數位沒有可行結果,移除上一位,重新檢索
    prev_nums.pop()


if __name__ == "__main__":
    ''' 主函數 '''
    print(search_num())

 

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