今日复习内容:DFS--回溯
1.介绍
回溯:就是DFS是一种,在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
回溯更强调:此路不通,另寻他路,走过的路需要打标记。
回溯法一般在DFS是基础上加上一些剪枝策略
2.个人理解
我理解的回溯,可以用来求排列
排列要求数字不重复,每次选择的数字都需要打标记,记为vis数组
哟输出当前排列,用于记录路径,记为path数组
简单来说,回溯就是先打标记,记录路径,然后下一层,回到上一层,再清除标记的过程。
我现在把它转化成代码:
def dfs(depth):# 当前为第depth个数字,0到depth - 1已经设置好if depth == n:print(path)return# 枚举第depth个数字for i in range(1,n + 1):# 数字i必须之前没有选择过if vis[i] is False:# 标记当前状态vis[i] = True# 记录当前路径path.append(i)# 进行下一轮搜索dfs(depth + 1)# 清空标记vis[i] = Falsepath.pop(-1)n = int(input('输入一个整数:'))
path = []
vis = [False] * (n + 1)
dfs(0)
运行结果:
回溯还可以用来求子集
给定n个数字,求子集:(我把它写成代码)
# 和买瓜那个题的思路差不多一样
n = int(input("请输入一个数字:"))
a = list(map(int,input().split()))
path = []
def dfs(depth):if depth == n:print(path)return# 该数字被选择的情况下path.append(a[depth])dfs(depth + 1)path.pop(-1)# 若是不选dfs(depth + 1)dfs(0)
运行结果:
例题1:N皇后
题目描述:
在N * N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意两个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框呈45度角的斜线上) ,你的任务是:对于给定的N,求出有多少种合法的放置方式。
输入描述:
输入中有一个正整数N <= 10,表示棋盘和皇后的数量。
输出描述:
为一个正整数,表示对应输入行的皇后的不同放置数量。
思路:
dfs枚举每一行放置的列;
标记的内容有:每列只能放一个,主对角线:x + y 副对角线:x - y + n
参考答案:
def dfs(depth):if depth == n:global ansans += 1return# 枚举第depth行放在哪列for i in range(1,n + 1):# 坐标为(depth,i)# 第i列先前未选择,主对角线,副对角线都未选择if vis1[i] is False and vis2[depth + i] is False and vis3[depth - i + n] is False:# 标记当前状态vis1[i] = Truevis2[depth + i] = Truevis3[depth - i + n] = Truedfs(depth + 1)# 清除标记vis1[i] = Falsevis2[depth + i] = Falsevis3[depth - i + n] = Falsen = int(input('请输入一个整数:'))
ans = 0
vis1 = [False] * (n + 1)
vis2 = [False] * (2 * n + 1)
vis3 = [False] * (2 * n + 1)
dfs(0)
print(ans)
运行结果:
例题2:小朋友崇拜圈
题目描述:
班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。
在一个游戏中,需要小朋友坐一个圈,每个小朋友都有自己最崇拜的小朋友在他的右手边。
求满足条件的圈最大多少人?
小朋友编号1,2,3...N
输入描述:
输入第一行,一个整数N(3 < N < 10^5)
接下来一行N个整数,空格分开。
输出描述:
要求输出一个整数,表示满足条件的最大圈的人数。
思路:
depth(x,length):走到x,已经走了length步
参考答案:
import sys
sys.setrecursionlimit(100000)
def dfs(x,length):# print(x,length)# 记录当前x,已经走了length步vis[x] = length# 如果下一步已经走过,则说明当前已经形成了一个圈if vis[a[x]]:# 更新最大圈global ansans = max(ans,length - vis[a[x] + 1])# 接着走下一步else:dfs(a[x],length + 1)n = int(input('请输入一个整数:'))
a = list(map(int,input().split()))
a = [0] + a
vis = [0] * (n + 1)
ans = 0
for i in range(1,n + 1):if vis[i] == 0:dfs(i,1)
print(ans)
OK,这篇就写到这里 ,下次继续!
ok,这篇就写到这里,下一篇继续!