深度優先搜尋--python
阿新 • • 發佈:2019-01-04
#coding:utf-8 import scrapy import xlwt, lxml import re, json import matplotlib.pyplot as plt import numpy as np import pylab from scipy import linalg import math ''' 深度優先搜尋DFS 理念:不斷深入,‘走到頭’回退(回溯思想) 一般所謂‘暴力列舉’搜尋都是指DFS 實現:一般使用堆疊,或者遞迴 用途:DFS過程中,能夠獲得的資訊: 時間戳,顏色,父子關係,高度 優點:由於只儲存了一條路徑,空間重複利用 #無論BFS,DFS找到解和解的‘位置’有關 ''' '''迴文劃分問題 給定一個字串s,將s劃分成若干子串,使得每一個字串都是迴文串。計算所有s的可能的劃分 eg:s='aab',-->'aa','b';'a','a','b' 在每一步都可以判斷中間結果是否為合法結果:回溯法--如果某一次劃分不合法,立刻對該分支限界 一個長度為n的字串,有n-1個位置可以截斷,每個位置可斷可不斷,故時間複雜度為O(2^(n-1)) ''' def isPalindrome(str,start,end):#判斷分段子串是否迴文,並返回布林型別(起始位置是否大於結束位置)【不是迴文串,則返回False】 while start<end and str[start]==str[end]: start+=1 end-=1 return start>=end def DFS(str,start,result,path): if start==len(str): if not path in result: result.append(path) print(result) return for i in range(start,len(str)): if isPalindrome(str,start,i): path.append(str[start:i+1])#是迴文串,則將路徑新增到結果列表中 DFS(str,i+1,result,path)#從下一段開始繼續劃分 path.pop()#向上一級回溯 # DFS('aab',0,[],[]) #類似的,給定僅包含數字的字串,返回所有可能的有效IP地址組合 # eg:'25525511135',返回'255.255.11.135';'255.255.111.35' #該問題插入三個分割位置;只有添加了第三個分割字元後,才能判斷當前劃分是否合法 # eg:2.5.5.25511135,才能判斷出是非法的 def isValid(str,start,end): if start<end: return math.floor(int(str[start:end])/256)<1 else: return False def DFS2(str,start,result,path): if start==len(str) and len(path)==4: result.append('.'.join(path)) print(result) return for i in range(start,len(str)): if isValid(str,start,i+1): path.append(str[start:i+1]) # print(path) DFS2(str,i+1,result,path) path.pop() # DFS2('25525511135',0,[],[]) ''' 八皇后問題: N*N矩陣,放置N個元素,且任意兩個元素不能處於同一行、同一列、同一(主/副)對角線上,問有多少種解法? ''' #全排列 # def isSwap(f,to): # bCan=True # for i in range(f,to): # if (s[to]==s[i]): # bCan=False # break # return bCan # # def permutation(f,to,c): # if f==to: # print(''.join(s)) # # return 1 # for i in range(f,to+1): # if(isSwap(f,i)==False): # continue # t=s[f]#將首字元和後續字元交換 # s[f]=s[i] # s[i] = t # permutation(f+1,to,c)#依次遞迴 # #交換回來保持原順序不變 # t = s[i] # s[i] = s[f] # s[f] = t # # print(''.join(s)) # # s=list('01234567') # l=len(s) # # print(l) # permutation(0,l-1,[]) ''' 分析:顯然任意一行有且僅有1個皇后,使用陣列queen[0...7]表示第i行的皇后放到哪一列 對於‘12345678’字串,呼叫全排列問題的程式碼,並且加入分支限界的條件判斷是否相互攻擊即可 此外,也可以使用深度優先的想法,將第i個皇后放置在第j列上,如果當前位置與其他皇后相互攻擊,則剪枝掉該結點[可拓展到n皇后問題] ''' def queen(arr,cur=0):#cur為當前行數 if cur==len(arr): print(arr) return for col in range(0,len(arr)): arr[cur],flag=col,True for row in range(0,cur): if arr[row]==col or abs(arr[cur]-arr[row])==cur-row:#剪枝條件,同列或同對角線 flag=False break if flag:#下一行 queen(arr,cur+1) # queen([None]*8) #數獨Sudoku【9*9】,初始化用‘.’表示,每行、每列、每個九宮格內,都是1-9這9個數字 def sudoku(arr): for i in range(len(arr)): for j in range(len(arr)): if arr[i][j]=='.': for k in range(len(arr)): arr[i][j]=1+k # print(arr) if isValid2(arr,i,j) and sudoku(arr): # print(arr) return True arr[i][j]='.' return False return True def isValid2(arr,x,y): print(arr) for i in range(len(arr)):#判斷除x行外的所有行某列 # print(arr[i][y]) if i!=x: # print(arr[i][y]) if arr[i][y]==arr[x][y]: # print(arr[x][y]) # print('1') return False for j in range(len(arr)):#判斷列 if j!=y and arr[x][j]==arr[x][y]: print('2') return False for i in range(3*(math.floor(x/3)),3*(math.floor(x/3)+1)): for j in range(3*(math.floor(y/3)),3*(math.floor(y/3)+1)): if (i !=x or j!=y)and arr[i][j]==arr[x][y]:#判斷小九宮格 print('3') return False return True ''' Tarjan演算法:深度優先 由Robert Tarjan在1979年發現的一種高效離線演算法。即,它要首先讀入所有的詢問(求一次LCA叫做一次訪問),然後並不一定按原來的順序處理這些訪問。 演算法時間複雜度O(N*α(N)+Q),其中α(x)不大於4,N表示問題規模,Q表示詢問次數 '''