DFS算法的介绍及手机解锁有效模式Python代码

题目:现有一个 3x3 规格的 Android 智能手机锁屏程序和两个正整数 m 和 n ,请计算出使用最少m 个键和最多 n个键可以解锁该屏幕的所有有效模式总数。

其中有效模式是指:
1、每个模式必须连接至少m个键和最多n个键;
2、所有的键都必须是不同的;
3、如果在模式中连接两个连续键的行通过任何其他键,则其他键必须在模式中选择,不允许跳过非选择键(如图);
4、顺序相关,单键有效(这里可能跟部分手机不同)。

在这里插入图片描述

输入:m,n
代表允许解锁的最少m个键和最多n个键
输出:
满足m和n个键数的所有有效模式的总数

可以通过DFS的方式先计算出刚好按下n个键时有多少种组合,然后求出S[n]至S[m]的和。
DFS的主要难度在于,下一步可以与当前的位置不直接相连。这时分两种情况:

  1. 普通的八个方向 (上下左右以及其45度夹角方向):
    若这八个方向都已经越界或走过了,则这时无路可走。若是普通的DFS则返回,但是九宫格解锁可以跳过相邻的一格。注意只能在这八个方向跳多一步,相当于踩着已经被按下的位置再沿着相同方向走一步。

2.其余的八个方向
其余的八个方向虽然不直接与当前位置直接相连,但是它与当前位置的连线不会触碰到其他位置,因此也可以直接到达。

DFS介绍:

DFS(Depth-First-Search)深度优先搜索,是计算机术语,是一种在开发爬虫早期使用较多的方法,是搜索算法的一种。它的目的是要达到被搜索结构的叶结点(即那些不包含任何超链的HTML文件) 。深度优先搜索沿着HTML文件上的超链走到不能再深入为止,然后返回到某一个HTML文件,再继续选择该HTML文件中的其他超链。当不再有其他超链可选择时,说明搜索已经结束。

深度优先遍历(Depth First Search)的主要思想是:

1、首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;

2、当没有未访问过的顶点时,则回到上一个顶点,继续试探别的顶点,直至所有的顶点都被访问过。

无向图的深度优先遍历图解:

在这里插入图片描述

对上无向图进行深度优先遍历,我们假设从A开始:

第1步:访问A。

第2步:访问B(A的邻接点)。 在第1步访问A之后,接下来应该访问的是A的邻接点,即"B,D,F"中的一个。但在本文的实现中,顶点ABCDEFGH是按照顺序存储,B在"D和F"的前面,因此,先访问B。

第3步:访问G(B的邻接点)。 和B相连只有"G"(A已经访问过了)

第4步:访问E(G的邻接点)。 在第3步访问了B的邻接点G之后,接下来应该访问G的邻接点,即"E和H"中一个(B已经被访问过,就不算在内)。而由于E在H之前,先访问E。

第5步:访问C(E的邻接点)。 和E相连只有"C"(G已经访问过了)。

第6步:访问D(C的邻接点)。

第7步:访问H。因为D没有未被访问的邻接点;因此,一直回溯到G访问G的另一个邻接点H。

第8步:访问(H的邻接点)F。

因此访问顺序是:A -> B -> G -> E -> C -> D -> H -> F

有向图的深度优先遍历图解:

在这里插入图片描述

对上有向图进行深度优先遍历,从A开始:

第1步:访问A。

第2步:访问(A的出度对应的字母)B。 在第1步访问A之后,接下来应该访问的是A的出度对应字母,即"B,C,F"中的一个。但在本文的实现中,顶点ABCDEFGH是按照顺序存储,B在"C和F"的前面,因此,先访问B。

第3步:访问(B的出度对应的字母)F。 B的出度对应字母只有F。

第4步:访问H(F的出度对应的字母)。 F的出度对应字母只有H。

第5步:访问(H的出度对应的字母)G。

第6步:访问(G的出度对应字母)E。 在第5步访问G之后,接下来应该访问的是G的出度对应字母,即"B,C,E"中的一个。但在本文的实现中,顶点B已经访问了,由于C在E前面,所以先访问C。

第7步:访问(C的出度对应的字母)D。

第8步:访问(C的出度对应字母)D。 在第7步访问C之后,接下来应该访问的是C的出度对应字母,即"B,D"中的一个。但在本文的实现中,顶点B已经访问了,所以访问D。

第9步:访问E。D无出度,所以一直回溯到G对应的另一个出度E。

因此访问顺序是:A -> B -> F -> H -> G -> C -> D -> E

手机锁屏解锁有效代码:

# Python3 dfs
# 所有方向
di = [(1,0), (-1,0), (0,1), (0,-1), (1,1), (-1,-1), (1,-1), (-1,1), (1,2), (1,-2), (-1,2), (-1,-2), (2,1), (2,-1),(-2,1),(-2,-1)]
# 可跨一个点的方向
ds = [(1,0), (-1,0), (0,1), (0,-1), (1,1), (-1,-1), (1,-1), (-1,1)]
# 解锁界面的9个点
nodes = {(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)}
#深度优先遍历代码实现:
def dfs(x, y, visited, count):
    visited.add((x, y))
    count -= 1
    ans = 0
    if count == 0:
        ans += 1
    else:
        for d in di:
            if (x+d[0], y+d[1]) in visited or (x+d[0], y+d[1]) not in nodes:
                if d not in ds:
                    continue
                else:
                    dx = d[0] * 2
                    dy = d[1] * 2
                    if (x+dx, y+dy) in nodes and (x+dx, y+dy) not in visited:
                        ans += dfs(x+dx, y+dy, visited, count)                       
            else:
                ans += dfs(x+d[0], y+d[1], visited, count)
    visited.remove((x, y))
    return ans
#初始化ans 
ans = [0] * 10
for count in range(1, 10):
    for i in range(3):
        for j in range(3):
            visited = set()
            ans[count] += dfs(i, j, visited, count)
# ans[i]即为i个键的结果数
#print(ans)
m=input("请输入允许最少连接多少个键:")
n=input("请输入允许最多连接多少个键:")
sum=0
m1=int(m)
n1=n
for i in range((int(n)-int(m))+1):
    sum=sum+ans[m1]
    m1=m1+1
print("至少连接",m,"个键和最多连接",n,"个的解锁有效模式一共有",sum,"种")
请输入允许最少连接多少个键:1
请输入允许最多连接多少个键:3
至少连接 1 个键和最多连接 3 个的解锁有效模式一共有 385 种

以上就是我个人对于DFS的一些理解和一个应用实例的代码,有什么意见或者建议欢迎在评论区留言

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值