BFS算法示例 - 解開密碼鎖的最少次數

概念

BFS(廣度優先搜索)是最簡便的圖的搜索算法之一,這一算法也是很多重要的圖的算法的原型。

BFS算法的核心思想就是把一些問題抽象成圖.

BFS相對DFS最主要的區別是: BFS找到的路徑一定是最短的,但代價是空間複雜度比DFS大很多.

BFS常出現的場景: 問題的本質就是讓你在一幅圖中找到從起點 start 到終點 target的最近距離,BFS算法其實就是在幹這事.

一般來說在找最短路徑的時候用BFS,其他時候還是用DFS多一些.

傳統的BFS框架是從起點開始向四周擴散,遇到終點時停止;而雙向BFS則是從起點和終點同時開始擴散,當兩邊有交集的時候停止.

使用雙向BFS的前提是,必須提前知道終點在哪裏.

無論傳統BFS還是雙向BFS,無論做不做優化,從Big O 的衡量標準看,空間複雜度都是一樣的.


例題: 打開密碼鎖

有一個帶四個圓形撥輪的轉盤鎖,每個撥輪都有0-9共10個數字, 每個撥輪可以上下旋轉: 例如把9變成0, 0變成9,每次旋轉只能將一個撥輪旋轉 一下

代碼(python)

import copy
from rich.console import Console
from rich import print

console = Console()  
res  = []

#~ 解開密碼鎖的最少次數


# 將密碼向上撥動一次
def plusOne(s,j):
    ch = []
    for i in s:
        ch.append(i)

    if ch[j] == '9':
        ch[j] = str(0)
    else:
        ch[j] = str(int(ch[j]) + 1  )
        
    # print(ch)    
    res = ''        
    for i in ch:
        res += i 
    return res 

# 將密碼向下撥動一次
def minusOne(s,j):
    ch = []
    for i in s:
        ch.append(i)

    if ch[j] == '0':
        ch[j] = str(9)
    else:
        ch[j] = str(int(ch[j]) - 1  )
        
    res = ''        
    for i in ch:
        res += i 
    return res 
                
# 傳統BFS,從起點出發擴散
def openLock(deadends,target):
    
    #記錄需要跳過的密碼
    deads = [] 
    for i in deadends:
        deads.append(i)
        
    #記錄已經窮舉過的密碼,防止走回頭路
    visited = []
    q = []
    
    #從起點開始啓動廣度優先搜索
    step = 0
    q.append("0000")
    visited.append("0000")
    
    while(q != None):
        sz = len(q)
        #將當前隊列中的所有節點向周圍擴散
        for i in range(sz):
            cur = q.pop(0)
            print(cur)
            
            #判斷密碼是否合法,是否到達終點
            if cur in deads:
                continue
            
            if cur  == target:
                return step
            
            # 將一個節點的未遍歷相鄰節點加入隊列
            for j in range(4):
                up = plusOne(cur,j)
                if up not in visited:
                    q.append(up)
                    visited.append(up)
                      
                down =  minusOne(cur,j)
                if down not in visited:
                    q.append(down)
                    visited.append(down)

        step += 1           
                    
    return -1                

# 雙向BFS                    
def both_openLock(deadends,target):
    
    #記錄需要跳過的密碼
    deads = [] 
    for i in deadends:
        deads.append(i)
        
    #記錄已經窮舉過的密碼,防止走回頭路
    visited = []
    q1 = []
    q2 = []
    
    #初始化起點和終點
    q1.append("0000")
    q2.append(target)
    
    step = 0
    
    while(q1 != None and q2 != None):
        print('q1 is ' + str(q1))
        print('q2 is ' + str(q2))
        temp = []
        for cur in q1:
            if cur in deads:
                continue
            if cur in q2:
                return step
            visited.append(cur)
            
            for j in range(4):
                up = plusOne(cur,j)
                if up not in visited:
                    temp.append(up)
                      
                down =  minusOne(cur,j)
                if down not in visited:
                   temp.append(down)
    
        step += 1
        print('temp is '+ str(temp))
        q1 = q2
        q2 = temp
    
              
                    
    return -1                


deadends = ["0007","5678"]
target = "2222"    
    
res =   both_openLock(deadends,target)  
print(res)




Flutter 寫的app, 需要源碼可以私信~~


最好的筆記軟件

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