PrepStack · Markdown HTML

Best-first boundary flood / priority flood

Ordered frontier and path · HTML

Formal shape

Seed every source boundary in a min-heap. Pop boundary cell u at effective height h; neighbor v receives effective height max(h,raw[v]), with local contribution derived from h versus raw[v].

Recognition signals

False friends

SignalWhy it is different
Single-source shortest pathThe heap key here is commonly effective boundary height, not an additive route sum.
Independent row or column scansA two-dimensional outlet can route around local extrema, so one-dimensional scans miss connectivity.

Core invariant

The heap is the boundary between discovered and unknown regions; its minimum fresh cell has the lowest possible controlling height at first contact from the exterior.

State, transition, and processing order

ItemDefinition
StateMulti-source min-heap, visited cells, raw values, effective height, and optional accumulated contribution.
TransitionFrom boundary u(h), discover v, mark it, add max(0,h-raw[v]), and push max(h,raw[v]) as its effective boundary.
Frontier / orderA heap for the entire discovered/unknown boundary, not merely the endpoint of one route.

Python skeleton

import heapq

def priority_flood(height):
    if not height or not height[0]:
        return 0
    rows, cols = len(height), len(height[0])
    heap, seen = [], set()
    for r in range(rows):
        for c in (0, cols - 1):
            if (r, c) not in seen:
                seen.add((r, c)); heapq.heappush(heap, (height[r][c], r, c))
    for c in range(cols):
        for r in (0, rows - 1):
            if (r, c) not in seen:
                seen.add((r, c)); heapq.heappush(heap, (height[r][c], r, c))
    total = 0
    while heap:
        level, r, c = heapq.heappop(heap)
        for dr, dc in ((1,0),(-1,0),(0,1),(0,-1)):
            nr, nc = r + dr, c + dc
            if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in seen:
                seen.add((nr, nc))
                total += max(0, level - height[nr][nc])
                heapq.heappush(heap, (max(level, height[nr][nc]), nr, nc))
    return total

Correctness sketch

  1. The exterior boundary contains every entry route from outside, so multi-source initialization omits no outlet.
  2. If a popped minimum effective boundary had a lower exterior route, that route's frontier would already have appeared earlier in the heap.
  3. A newly reached cell's minimum controlling height is exactly max(current boundary, own height); any gap below the boundary is the locally constrained amount.

Complexity

TimeSpaceParameters
O(RC log(RC))O(RC)Each cell is discovered and pushed at most once; the heap may contain O(RC) cells.

Edge cases

Error patterns

PatternWhy it fails / fix
Pushing raw instead of effective heightA low cell falsely becomes a new outlet; push max(level,raw).
Starting from one cornerOther exterior entries are omitted, corrupting the boundary model.
Marking only after popSeveral boundary neighbors can push one cell and count its contribution repeatedly.

Selection and exclusion rules

RelationTemplateBoundary
shares greedy proof skeletonDijkstra nonnegative shortest pathReasoning about finality of a minimum fresh pop.
shares max relaxationMinimax / bottleneck Dijkstraeffective=max(previous,raw), but priority flood launches from every outer boundary.

Original micro-example

PartDetail
ResultThe total constrained amount is 6.
SetupA ring of height 6 encloses cells of height 2 and 4 with no lower outlet.
TraceBoundary 6 reaches both: effective level of 2 becomes 6 and contributes 4; the 4 cell contributes 2.

Recall prompts

My notes