使用回溯计算屏幕锁定模式的问题

Posted

技术标签:

【中文标题】使用回溯计算屏幕锁定模式的问题【英文标题】:Problem counting screen locking patterns with backtracking 【发布时间】:2019-08-28 15:53:28 【问题描述】:

问题是计算从给定的长度为 n 的路径的数量 图中的顶点,例如用于解锁 android 设备。我正在尝试使用回溯来解决它,但我不正确,我仍在学习如何使用它。所以这是我一直在尝试的一些代码

G = 
    'a': set('bed'),
    'b': set('cfeda'),
    'c': set('feb'),
    'd': set('abehg'),
    'e': set('bcfihgda'),
    'f': set('ciheb'),
    'g': set('deh'),
    'h': set('efigd'),
    'i': set('fhe')


result = 0


def count_patterns(node, length):
    if length == 1:
        return len(G[node])
    global result
    for neighbor in G[node]:
        result += count_patterns(neighbor, length - 1) - 1
    return result

我希望 count_patterns('a',2) 返回 15 并且它确实返回它;然而,对于 n>2 到目前为止,所有结果都是错误的。我认为一定是我实际上并没有跟踪访问过的节点,例如,如果在 n = 3 时采用这条路线 a -> b -> c 当它回溯到 a -> b 时,它可以采用 a -> b -> a 这是错误的,因此它不能将节点的父节点作为邻居,我知道问题但是 我不知道如何解决它。

【问题讨论】:

为什么结果是全局的?如果您将global result 更改为result = 0,看起来这很好用 你是对的,但即使这样我得到了错误的结果,但现在比以前更准确。对于 count_patterns('a',4) --> 299 它应该返回我 256。有什么想法吗?? 递归调用后的- 1 是什么? 这是不计算来自哪里的边,例如如果采用以下路径 a -> b -> c make counter_patterns('c', 1) 将返回'的邻居数c' 是 'b', 'e' 和 'f' 但 'b' 是从哪里来的。 “就像用于解锁 Android 设备。”:这不是一个明确的规范。例如,在 Android 上,您可以在不使用 4 的情况下不连接 1 和 7。还有其他规则。不要与此 Android 系统进行比较,请指定路径必须遵守的所有规则,... 明确。 【参考方案1】:

首先,您不需要最后一个 -1。所以,

result += count_patterns(neighbor, length - 1) - 1

应该变成

result += count_patterns(neighbor, length - 1)

您的代码的主要问题是,例如,如果您从 a->b 到 b->a,您会将其视为长度为 2 的路径。但事实并非如此。路径不应该有重复的顶点。有两种方法可以解决这个问题:(我只提主要思想)

    拥有一个具有布尔值(真或假)的全局已访问数组。如果您有 n 个节点,则此数组的容量应与节点数一样多。然后,您将代码更改如下:(伪代码)

``

def count_patterns(node, length):
    if length == 1:
        return len(G[node])
    global result
    for neighbor in G[node]:
        if neighbor is not visited
             mark neighbor as visited
             result += count_patterns(neighbor, length - 1)
             mark neighbor as unvisited //This is very important
    return result

``

您需要“将邻居标记为未访问”的原因是您不想在特定分支中重复某个顶点;但是您希望在从递归调用返回后能够在另一条路径上使用它。

    您可以将第三个参数传递给您的函数,它是您目前选择的顶点的列表;然后,如果您不在列表中,则仅选择一个新顶点。你也更新了列表:

``

def count_patterns(node, length, list):
    if length == 1:
        return len(G[node])
    global result
    for neighbor in G[node]:

        if neighbor is not in list

             result += count_patterns(neighbor, length - 1, list.append(neighbor))
    return result

``

我个人更喜欢第一种方式,因为它会更快更简单。

【讨论】:

以上是关于使用回溯计算屏幕锁定模式的问题的主要内容,如果未能解决你的问题,请参考以下文章

Win10 如何设置自动锁定屏幕

在锁定屏幕模式和访问其他应用程序时录制语音和说话和收听实时聊天

Flutter:如何按需设置和锁定屏幕方向

使用 AVAudioPlayer 控制锁定屏幕上的音频

在 iOS 14 中锁定屏幕方向

iOS AVPlayer:屏幕锁定时暂停视频