you can find the description here and you can find the code here

as long as there are no upper-cased direct loops (ie, A - B), simple dfs works for both cases:

for part 1:

def dfs1(g, node, visited):
    if node == "end":
        return 1
    res = 0
    for nn in g[node]:    
        if nn.isupper() or nn not in visited:
            visited.add(nn) 
            res += dfs1(g, nn, visited)
            visited.discard(nn)    
    return res

for part 2:

def dfs2(g, node, visited, used):
    if node == "end":        
        return 1
    res = 0
    for nn in g[node]:
        if nn.isupper():    
            res += dfs2(g, nn, visited, used)    
        elif nn in visited and nn != "start" and not used:
            res += dfs2(g, nn, visited, True)
        elif nn not in visited:
            visited.add(nn)
            res += dfs2(g, nn, visited, used)
            visited.discard(nn)
    return res