<p>You are given a <strong>0-indexed</strong> 2D matrix <code>grid</code> of size <code>m x n</code>, where <code>(r, c)</code> represents:</p>

<ul>
	<li>A <strong>land</strong> cell if <code>grid[r][c] = 0</code>, or</li>
	<li>A <strong>water</strong> cell containing <code>grid[r][c]</code> fish, if <code>grid[r][c] &gt; 0</code>.</li>
</ul>

<p>A fisher can start at any <strong>water</strong> cell <code>(r, c)</code> and can do the following operations any number of times:</p>

<ul>
	<li>Catch all the fish at cell <code>(r, c)</code>, or</li>
	<li>Move to any adjacent <strong>water</strong> cell.</li>
</ul>

<p>Return <em>the <strong>maximum</strong> number of fish the fisher can catch if he chooses his starting cell optimally, or </em><code>0</code> if no water cell exists.</p>

<p>An <strong>adjacent</strong> cell of the cell <code>(r, c)</code>, is one of the cells <code>(r, c + 1)</code>, <code>(r, c - 1)</code>, <code>(r + 1, c)</code> or <code>(r - 1, c)</code> if it exists.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2023/03/29/example.png" style="width: 241px; height: 161px;" />
<pre>
<strong>Input:</strong> grid = [[0,2,1,0],[4,0,0,3],[1,0,0,4],[0,3,2,0]]
<strong>Output:</strong> 7
<strong>Explanation:</strong> The fisher can start at cell <code>(1,3)</code> and collect 3 fish, then move to cell <code>(2,3)</code>&nbsp;and collect 4 fish.
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2023/03/29/example2.png" />
<pre>
<strong>Input:</strong> grid = [[1,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]]
<strong>Output:</strong> 1
<strong>Explanation:</strong> The fisher can start at cells (0,0) or (3,3) and collect a single fish. 
</pre>

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

<ul>
	<li><code>m == grid.length</code></li>
	<li><code>n == grid[i].length</code></li>
	<li><code>1 &lt;= m, n &lt;= 10</code></li>
	<li><code>0 &lt;= grid[i][j] &lt;= 10</code></li>
</ul>

class Solution:
    def findMaxFish(self, grid: List[List[int]]) -> int:
        def visit(r, c):
            res = grid[r][c]
            grid[r][c] = 0
            for next_r, next_c in [(r+1, c), (r-1, c), (r, c+1), (r, c-1)]:
                if 0 <= next_r < R and 0 <= next_c < C and grid[next_r][next_c] != 0:
                    res += visit(next_r, next_c)
            return res

        
        def find_parent(r, c):
            if (r, c) != parent[(r, c)]:
                pr, pc = parent[(r, c)]
                parent[(r, c)] = find_parent(pr, pc)
            return parent[(r, c)]
        
        def union(r1, c1, r2, c2):
            (pr1, pc1), (pr2, pc2) = find_parent(r1, c1), find_parent(r2, c2)
            if (pr1, pc1) != (pr2, pc2):
                parent[(pr2, pc2)] = (pr1, pc1)
                num_fish[(pr1, pc1)] += num_fish[(pr2, pc2)]

        R, C = len(grid), len(grid[0])
        parent = {(r, c): (r, c) for r in range(R) for c in range(C)}
        num_fish = {(r, c): grid[r][c] for r in range(R) for c in range(C)}
        answer = 0
        for r in range(R):
            for c in range(C):
                # find a water cell and compute the sum of fishes among all connected water cells
                if grid[r][c] != 0:
                    # BFS

                    # queue = [(r, c)]
                    # total = 0
                    # while queue:
                    #     cur_r, cur_c = queue.pop()
                    #     total += grid[cur_r][cur_c]
                    #     grid[cur_r][cur_c] = 0
                    #     for next_r, next_c in [(cur_r+1, cur_c), (cur_r-1, cur_c), (cur_r, cur_c+1), (cur_r, cur_c-1)]:
                    #         if 0 <= next_r < R and 0 <= next_c < C and grid[next_r][next_c] != 0:
                    #             queue.append((next_r, next_c))
                    # answer = max(answer, total)

                    # DFS
                    # total = visit(r, c)
                    # answer = max(answer, total)

                    # Union find
                    for next_r, next_c in [(r+1, c), (r-1, c), (r, c+1), (r, c-1)]:
                        if 0 <= next_r < R and 0 <= next_c < C and grid[next_r][next_c] != 0:
                            union(r, c, next_r, next_c)
                    answer = max(answer, num_fish[find_parent(r, c)])

        return answer
302