pythonrecursiongraphdirected-acyclic-graphslongest-path

Function to find the highest score path in a graph with python


I'm trying to make a function to find the highest score in a directed graph. I do have a start node and can't go throught the same node twice. I've tried to use recursive to get the sum of values until I hit one end node. Then I would call back my function to the start node and try other option ultil I hit another. And so on.

My problem is that when i return to a node with more than one path, the score value for this node is the sum of all paths it can take. And I only want the sum of one specific path.

Here is my code so far:


caminho = list()
def maxscore(start, parentals, score):
    global caminho
    parentals += start + '|'

    if len(graph[start]) > 0:
        for i in graph[start]:
            if i not in parentals.split('|'):
                value = graph[start][i]
                if value:
                    score += value

                func = maxscore(i, parentals, score)

            else:
                continue

        if func[0] > score:
            score = func[0]
            caminho = parentals.split('|')

        return score, caminho

    else:
        return score, start

graph = {
    'a': {'b': 2, 'c': 4},
    'b': {'d': 5},
    'c': {'a': 1, 'e': 3},
    'd': {'f': 4},
    'e': {'b': 2, 'f': 3, 'g': 2},
    'f': {},
    'g': {}
}

print(maxscore('a', '', 0))

How could I make it work to return in the end only the best score with the path(caminho) it took.

Sorry if I couldn't make myself clear enough. Feel free to ask any questions.


Solution

  • Here is an approach:

    def maxscore(start, path, score):
        best_score = -1
        best_i = None
        best_path = None
    
        current_path = path + [start]
        for i in graph[start]:
            if not i in path:
                score_i, path_i = maxscore(i, current_path, score + graph[start][i])
                if score_i > best_score:
                    best_score = score_i
                    best_i = i
                    best_path = path_i
        if best_i is None:
            return score, current_path
        else:
            return best_score, best_path
    
    graph = {
        'a': {'b': 2, 'c': 4},
        'b': {'d': 5},
        'c': {'a': 1, 'e': 3},
        'd': {'f': 4},
        'e': {'b': 2, 'f': 3, 'g': 2},
        'f': {},
        'g': {}
    }
    
    print(maxscore('a', [], 0))
    

    Output:

    (18, ['a', 'c', 'e', 'b', 'd', 'f'])
    

    Notes:

    PS: After revising the code, it can be shortened a bit. best_iis not really needed, and the test if best_i is None can be replaced by if best_path is None.

    Also, if you need the path in the string form, you can print("|".join(best_path)).