1. 程式人生 > >深度優先搜尋--python

深度優先搜尋--python

#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表示詢問次數

'''