<p>There is an <strong>undirected</strong> graph with <code>n</code> nodes, numbered from <code>0</code> to <code>n - 1</code>.</p>

<p>You are given a <strong>0-indexed</strong> integer array <code>scores</code> of length <code>n</code> where <code>scores[i]</code> denotes the score of node <code>i</code>. You are also given a 2D integer array <code>edges</code> where <code>edges[i] = [a<sub>i</sub>, b<sub>i</sub>]</code> denotes that there exists an <strong>undirected</strong> edge connecting nodes <code>a<sub>i</sub></code> and <code>b<sub>i</sub></code>.</p>

<p>A node sequence is <b>valid</b> if it meets the following conditions:</p>

<ul>
	<li>There is an edge connecting every pair of <strong>adjacent</strong> nodes in the sequence.</li>
	<li>No node appears more than once in the sequence.</li>
</ul>

<p>The score of a node sequence is defined as the <strong>sum</strong> of the scores of the nodes in the sequence.</p>

<p>Return <em>the <strong>maximum score</strong> of a valid node sequence with a length of </em><code>4</code><em>. </em>If no such sequence exists, return<em> </em><code>-1</code>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/04/15/ex1new3.png" style="width: 290px; height: 215px;" />
<pre>
<strong>Input:</strong> scores = [5,2,9,8,4], edges = [[0,1],[1,2],[2,3],[0,2],[1,3],[2,4]]
<strong>Output:</strong> 24
<strong>Explanation:</strong> The figure above shows the graph and the chosen node sequence [0,1,2,3].
The score of the node sequence is 5 + 2 + 9 + 8 = 24.
It can be shown that no other node sequence has a score of more than 24.
Note that the sequences [3,1,2,0] and [1,0,2,3] are also valid and have a score of 24.
The sequence [0,3,2,4] is not valid since no edge connects nodes 0 and 3.
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/03/17/ex2.png" style="width: 333px; height: 151px;" />
<pre>
<strong>Input:</strong> scores = [9,20,6,4,11,12], edges = [[0,3],[5,3],[2,4],[1,3]]
<strong>Output:</strong> -1
<strong>Explanation:</strong> The figure above shows the graph.
There are no valid node sequences of length 4, so we return -1.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>n == scores.length</code></li>
	<li><code>4 &lt;= n &lt;= 5 * 10<sup>4</sup></code></li>
	<li><code>1 &lt;= scores[i] &lt;= 10<sup>8</sup></code></li>
	<li><code>0 &lt;= edges.length &lt;= 5 * 10<sup>4</sup></code></li>
	<li><code>edges[i].length == 2</code></li>
	<li><code>0 &lt;= a<sub>i</sub>, b<sub>i</sub> &lt;= n - 1</code></li>
	<li><code>a<sub>i</sub> != b<sub>i</sub></code></li>
	<li>There are no duplicate edges.</li>
</ul>

from collections import defaultdict, deque
import heapq

class Solution:
    def maximumScore(self, scores: List[int], edges: List[List[int]]) -> int:
        adj = defaultdict(list)
        for edge in edges:
            adj[edge[0]].append(edge[1])
            adj[edge[1]].append(edge[0])

        max_edges = defaultdict(list)
        for node in range(len(scores)):
            max_edges[node] = heapq.nlargest(3, [(scores[nbr], nbr) for nbr in adj[node]])

        def best_continuation(max_edges_first_node, max_edges_second_node, used_nodes, scores):
            if max_edges_first_node and max_edges_first_node[0][1] not in used_nodes:
                used_node = max_edges_first_node[0][1]
            elif len(max_edges_first_node) > 1 and max_edges_first_node[1][1] not in used_nodes:
                used_node = max_edges_first_node[1][1]
            elif len(max_edges_first_node) > 2 and max_edges_first_node[2][1] not in used_nodes:
                used_node = max_edges_first_node[2][1]
            else:
                return 0, False
            score = scores[used_node]
            used_nodes_three = used_nodes | {used_node}
            if max_edges_second_node and max_edges_second_node[0][1] not in used_nodes_three:
                used_node = max_edges_second_node[0][1]
            elif len(max_edges_second_node) > 1 and max_edges_second_node[1][1] not in used_nodes_three:
                used_node = max_edges_second_node[1][1]
            elif len(max_edges_second_node) > 2 and max_edges_second_node[2][1] not in used_nodes_three:
                used_node = max_edges_second_node[2][1]
            else:
                return 0, False
            return score + scores[used_node], True
            

        ans = -1
        for edge in edges:
            edge_score = scores[edge[0]] + scores[edge[1]]
            used_nodes = set([edge[0], edge[1]])
            max_edges_first_node = max_edges[edge[0]]
            max_edges_second_node = max_edges[edge[1]]
            best_cont, is_valid = best_continuation(max_edges_first_node, max_edges_second_node, used_nodes, scores)
            best_cont1, is_valid1 = best_continuation(max_edges_second_node, max_edges_first_node, used_nodes, scores)
            if not is_valid and not is_valid1:
                continue
            maybe_ans = edge_score + max(best_cont if is_valid else -1, best_cont1 if is_valid1 else -1)
            ans = max(maybe_ans, ans)
        return ans

    # def maybe_update_ans(ans, scores, path):
    #     poss_ans = sum([scores[x] for x in path])
    #     return max(ans, poss_ans)
    
    # ans = -1
    # for initial_node in range(len(scores)):
    #     # (node to visit, depth, path before node)
    #     to_visit = deque([(initial_node, 0, [])])
    #     while to_visit:
    #         node, depth, path = to_visit.pop()
    #         if depth == 3:
    #             ans = maybe_update_ans(ans, scores, path + [node])
    #             continue
    #         for nbr_node in adj[node]:
    #             if nbr_node not in path:
    #                 to_visit.append((nbr_node, depth + 1, path + [node]))
    # return ans
     

1706