#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表示询问次数
'''