两种DFS的实现
# def dfs(s, t): # 区间范围[s:t]
# if s == t: # 终止条件
# print(a[0:n])
# else:
# for i in range(s, t + 1): # 交换首元素,从s到t交换一次
# a[s], a[i] = a[i], a[s]
# dfs(s + 1, t)
# a[i], a[s] = a[s], a[i]
#
#
# a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# n = 3
# dfs(0, n - 1)
# 主流DFS写法
# def dfs(s, t): # 区间范围[s:t]
# if s == t: # 终止条件
# print(b[0:n])
# else:
# for i in range(t): # 从0-n开始作为首元素
# if vis[i]== False: # 检查没被用过的
# vis[i]=True
# b[s]=a[i] # 存排列
# dfs(s + 1, t)
# vis[i]=False
#
#
# a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# b=[0]*10 # 记录全排列
# vis = [False]*10 # 检查是否用过
# n = 3
# dfs(0, n) #前n个数的全排列
DFS实现排列
# DFS 实现排列,二进制输出
# vis = [0]*10
# def dfs(k): # 深搜到第k个
# if k==4:
# b=map(str,vis[:4])
# print(''.join(b))
#
# # for i in range(4):
# # print(vis[i],end=' ')
# # print()
# else:
# vis[k]=0 # 不选第k个
# dfs(k+1)
# vis[k]=1 # 选第k个
# dfs(k+1)
# dfs(0)
def dfs(k): # 深搜到第k个,以10进制输出
if k==3:
for i in range(3):
if vis[i]==1:
print(a[i],end=' ')
print()
else:
vis[k]=0 # 不选第k个
dfs(k+1)
vis[k]=1 # 选第k个
dfs(k+1)
vis = [0]*10
a=[1,2,3,4,5,6,7,8,9,10]
dfs(0)
迷宫
# bfs搜索,顺便记录路径
# dfs反向搜索记录路径并输出
def dfs(x, y): # 从(x,y)处开始搜索
if (x==29 and y==49): # 到达终点
return 1
if vis[x][y]==1 : # 走过该点,没走出去,说明出不去
return 0
vis[x][y]=1
if mp[x][y] =='L':
return dfs(x-1,y)
if mp[x][y] =='R':
return dfs(x+1,y)
if mp[x][y] =='U':
return dfs(x,y+1)
if mp[x][y] =='D':
return dfs(x,y-1)
track=[]
# 30 行 50 列
mp = [[''*50]for i in range(30)] # 存储迷宫,预先分配大小,不然赋值会报错
for i in range(10): # 存储迷宫
mp[i] = list(input())
vis = [[0]*50 for i in range(30)]
dfs(0,0)
# 记录路径没有写!!
寒假作业题(排列+DFS)
def dfs(num): # (1-13)
global ans
if(num ==13): #终止条件
if b[10]==b[11]*b[12]: # 将除法转为乘法更快速
ans+=1
return
# 剪枝处理
if num ==4 and b[1]+b[2]!=b[3] : return
if num ==7 and b[4]-b[5]!=b[6] : return
if num ==10 and b[7]*b[8]!=b[9] : return
for i in range(1,14): # 按字典序遍历
if not vis[i]:
b[num]=i
vis[i]=1 # 保护现场
dfs(num+1) # 相当于固定了前面几个,遍历后面几个
vis[i]=0 #恢复现场
ans =0
b=[0]*15 # 记录排列
vis=[0]*15 # 记录是否遍历
dfs(1) # (1-13)
print(ans)
找被淹没岛屿,DFS+连通分量
import sys
sys.setrecursionlimit(60000) # 设置最大递归深度,默认递归深度有点小,不设置递归会出问题
def dfs(x,y):
d=[(-1,0),(0,1),(1,0),(0,-1)] # 左 上 右 下
global flag
global vis # 判断是否走过
global mp # 地图
vis[x][y] =1
if mp[x][y+1]=='#' and mp[x][y-1] =='#' and mp[x+1][y]=='#' and mp[x-1][y]=='#':
# 说明点(x,y)四周都是陆地
flag = 1 # 高地标记,不会被淹没
for i in range(4):
nx=x+d[i][0]
ny=y+d[i][1]
if vis[nx][ny] ==0 and mp[nx][ny] =='#':
# 如果当前没有遍历点(nx,ny)同时地图上面该点不是陆地
dfs(nx,ny)
n=int(input())
mp = [] # 记录地图
for i in range(n):
mp.append(list(input()))
vis =[] # 判断是否走过
for i in range(n):
vis.append([0]*n)
ans =0
for i in range(n): # 遍历每一点
for j in range(n):
if vis[i][j] ==0 and mp[i][j] =='#': # 相当于找连通分量
flag = 0
dfs(i,j)
if flag==0:
ans+=1
print(ans)
DFS问题
import sys
sys.setrecursionlimit(300000) # 设置最大递归深度,默认递归深度有点小,不设置递归会出问题
def dfs(u,fa):
# 计算当前结点 左子, 右子,和父结点的连通度
global num ,maxnum # 教父数量
d[u]=1 # 最少存在一个,即叶子结点
temp =0
for v in edges[u]:
if v == fa: continue # 父结点不再遍历
dfs(v,u) # 递归叶子节点
d[u]=d[u]+d[v] # 计算当前结点数量
temp =max(temp,d[v]) # 计算子节点当前最大连通块数量
temp = max(temp,n-d[u]) # 计算当前结点最大连通块数量
if temp<maxnum: # 更新教父
maxnum = temp
num =1
ans[1]=u
elif temp ==maxnum: # 发现疑似教父
num+=1
ans[num]=u
maxnum = int(1e9)
n = int(input())
d = [0]*(n+1) # 记录以u为子树的结点数量
ans = [0] * (n+1) # 记录教父
num = 0 # 记录教父数量
edges =[[]for i in range(n+1)] # 存储邻接边
for i in range(n-1): # 以邻接边形式存储树
a,b = map(int,input().split())
edges[a].append(b)
edges[b].append(a)
dfs(1,0)
s=sorted(ans[1:num+1])
for i in range(num): # 根据教父数量打印教父,当有相同最小值时会出现多个教父
print(s[i],end=' ')
DFS搜索问题
import sys
sys.setrecursionlimit(300000) # 设置最大递归深度,默认递归深度有点小,不设置递归会出问题
def dfs(x,y,c,s): # (X,Y,count,sum)
global sum_num,ans
if 2*s > sum_num : # 剪枝
return
if 2*s ==sum_num: # 找到合适的方格
if ans>c and vis[0][0]==1: # 找到了更优解更新
ans =c
vis[x][y]=1 # 保存现场
dir = [(-1,0),(0,1),(1,0),(0,-1)] # 左上右下
for u ,v in dir: #往四个方向遍历
nx,ny = x+u,y+v
if(nx>=0 and ny>=0 and nx<n and ny <n): # x,y 取值都是[0,n-1]
if vis[nx][ny]==0: #没有遍历过
dfs(nx,ny,c+1,s+a[x][y])
vis[x][y]=0 #恢复现场
m,n = map(int,input().split()) # 读入输入大小,n*m
a = [list(map(int,input().split())) for _ in range(n)] #读入数据
vis = [[0]*m for _ in range(n)] # 判断是否走过
sum_num = 0
for i in a: # 计算总和
sum_num += sum(i)
ans = 1000
dfs(0,0,0,0)
print(ans)
找路径问题
import sys
sys.setrecursionlimit(300000) # 设置最大递归深度,默认递归深度有点小,不设置递归会出问题
def dfs(x,y):
if a[x]<0 or b[y]<0: return # 直接剪枝
if x==n-1 and y==n-1: # 到达终点
if sum(a)!=0 or sum(b)!=0 : # 说明不是正确顺序
return
for i in range(len(path)):
print(path[i],end=' ')
# 遍历
d = [(1,0),(-1,0),(0,1),(0,-1)]
for u,v in d:
nx=x+u;ny=y+v
if 0<=nx<n and 0<=ny<n and vis[nx][ny]==0: # 判断坐标是否合法,并且没有被访问
vis[nx][ny]=1 #保护现场
path.append(nx*n+ny) # 进栈,保存路径
a[nx]-=1
b[ny]-=1
dfs(nx,ny)
path.pop() # 出栈,那条路走不通
a[nx]+=1
b[ny]+=1
vis[nx][ny]=0 # 恢复现场,之前那条路走不通,换路
n = int(input())
path = [] # 创建一个栈用于保存路径
# 保存射箭数
b = list(map(int,input().split())) # 西——> 东 x方向
a = list(map(int,input().split())) # 北——> 南 y方向
vis = [[0]*n for _ in range(n)] # 用于判断是否到达
# 从(0,0) 开始搜索
vis[0][0]=1
a[0]-=1
b[0]-=1
path.append(0)
dfs(0,0)
剪枝搜索
import sys
sys.setrecursionlimit(300000) # 设置最大递归深度,默认递归深度有点小,不设置递归会出问题
def dfs(n):
global cnt
if n>4 and m[1]+m[2]+m[3]+m[4] !=34 :return # 剪枝
if n>8 and m[5]+m[6]+m[7]+m[8] !=34 :return # 剪枝
if n>12 and m[9]+m[10]+m[11]+m[12] !=34 :return # 剪枝
if n>13 and m[4]+m[7]+m[10]+m[13] !=34 :return # 剪枝
if n>14 and m[2]+m[6]+m[10]+m[14] !=34 :return # 剪枝
if n>15 and m[3]+m[7]+m[11]+m[15] !=34 :return # 剪枝
if n>16 and m[4]+m[8]+m[12]+m[16] !=34 \
or m[13]+m[14]+m[15]+m[16] !=34\
or m[1]+m[6]+m[11]+m[16] !=34 :return # 剪枝
if n==17:
cnt+=1
for i in range(2,17):
if(vis[i]==0):
m[n]=i #给m赋值
vis[i]=1
dfs(n+1)
vis[i]=0
cnt = 0 # 有多少种方案
m = [0]*17
m[1]=1 # 左上角固定为1
vis = [0]*17 # 看是否使用
vis[1]=1
dfs(1)
print(cnt)
# 1 -- 16
感悟(要保存现场,恢复现场,读入矩阵,一个到达矩阵(与读入矩阵相同),左上右下,遍历,可以通过栈来记录路径,同时剪枝优化)