Artotim
Artotim

Reputation: 85

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.

Upvotes: 3

Views: 1426

Answers (2)

JohanC
JohanC

Reputation: 80329

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:

  • In the code of the question caminho and parentals served the same function. Just having a list is easier to work with than with a string.
  • In the for-loop, we test each of the edges. If the end-node of the edge is not yet in the path, we calculate the maximum score following that edge. We have to compare each of the possible edges and keep the one with the best score. We can only return from maxscore() after testing all possible edges.
  • If no free edge was found, we just return the current score and path
  • If free edges were found, we return the score and path of the best edge

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

Upvotes: 1

DPP_Iacob_Gabriel
DPP_Iacob_Gabriel

Reputation: 21

You probably want to send the score variable by value, but you are sending it by reference, therefore all the possible paths' scores are added to it.

This is my approach:

def maxscore(start, parentals, score):
    newParentals = parentals + start + '|'
    print newParentals, score
    scores = []
    if graph[start]:
        for nextNode in graph[start]:
            if nextNode not in newParentals.split('|'):
                scores.append(maxscore(nextNode, newParentals, score + graph[start][nextNode]))
        return sorted(scores)[-1]
    else:
        return score

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))

And this is what gets printed:

a| 0
a|c| 4
a|c|e| 7
a|c|e|b| 9
a|c|e|b|d| 14
a|c|e|b|d|f| 18
a|c|e|g| 9
a|c|e|f| 10
a|b| 2
a|b|d| 7
a|b|d|f| 11
18

You can see how it checks all possible paths, and then picks the highest score :D

Upvotes: 2

Related Questions