问题
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)
- 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.
- 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