Problem counting screen locking patterns with backtracking

让人想犯罪 __ 提交于 2019-12-24 07:39:29

问题


The problem is counting the number of paths of length n from a given vertex in a graph like the used to unlock Android devices.I'm trying to use backtracking to solve it but I don't get right, I'm I'm still learning how to use it. So here is some code I've been trying

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

I expect the count_patterns('a',2) to return 15 and it does return it; however, for n>2 all the results are wrong by far. I think it must be that I don't actually getting track of the node visited, for example if takes this route for n = 3 a -> b -> c when it backtracks to a -> b it can take a -> b -> a which is wrong so it cannot take the parent of the node as a neighbor, I know the problem but I don't know how to fix it.


回答1:


First of all, you don't need the last -1. So,

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

Should become

result += count_patterns(neighbor, length - 1)

The main problem with your code is that if you go, for example, from a->b and then b->a, you count this as a path of length 2. But it's not. A path shouldn't have repeated vertices. There are two ways you can deal with this: (I will only mention the main idea)

  1. Have a global visited array that has boolean values (true or false). If you have n nodes, this array should have a capacity as much as the number of nodes. Then, you change your code as follows: (pseudocode)

``

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

``

The reason that you need to "mark neighbor as unvisited" is because you don't want to repeat a vertex in a specific branch; but you want to be able to use it on another path after you have returned from your recursive call.

  1. You can just pass a third argument to your function which is a list of the vertices you've picked so far; then you only pick a new vertex if you it's not in the list. And you update the list as well:

``

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

``

I personally, prefer the first way because it's gonna be faster and simpler.



来源:https://stackoverflow.com/questions/57696149/problem-counting-screen-locking-patterns-with-backtracking

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!