## 1. Abridged problem statement

A rectangular lake is divided into an `N × M` grid. Each cell has a water flow vector encoded by a digit:

- `0`: `(0, 0)`
- `1`: `(0, -1)`
- `2`: `(0, 1)`
- `3`: `(1, 0)`
- `4`: `(-1, 0)`

Peter starts at the center of one cell, and his boat starts at the center of another.  
At any cell center, Peter chooses one of the same five vectors as his own swimming vector; his real velocity is:

```text
water flow + Peter's chosen vector
```

He keeps this velocity until reaching another cell center, where he may choose again. He may also wait at a center by cancelling the flow.

The boat has no own movement, so it only drifts with the water flow.

Peter is saved if:

1. he reaches the shore, or
2. he reaches the exact same point as the boat, not necessarily at a cell center.

Find the minimum time needed, or print `SOS` if impossible.

Constraints:

```text
1 ≤ N, M ≤ 500
```

---

## 2. Detailed editorial

### Geometry model

Cell `(x, y)` has its center at integer coordinates. Peter and the boat start at centers.

The flow vector in a cell is one of:

```text
0: (0, 0)
1: (0, -1)
2: (0, 1)
3: (1, 0)
4: (-1, 0)
```

Peter may add one of the same five vectors.

Therefore Peter’s resulting velocity can be:

- zero, meaning he stays still,
- speed `1` horizontally/vertically,
- speed `√2` diagonally,
- speed `2` horizontally/vertically if he swims with the flow.

Whenever Peter moves from one cell center to another:

- if velocity has component `±2`, he reaches the next center in `0.5` minutes,
- otherwise he reaches the next center in `1` minute.

Thus all Peter-to-center travel times are multiples of `0.5`.

---

### Step 1: shortest times for Peter to reach every cell center

We build a graph whose vertices are grid cells.

From a cell, try all five possible swimming vectors. Add it to the flow vector. If the result is not zero, Peter moves in that direction to a neighboring center.

The edge cost is:

- `1` half-minute if speed is `2`, i.e. actual time `0.5`,
- `2` half-minutes otherwise, i.e. actual time `1`.

So we compute shortest distances in units of half-minutes.

Because all edge weights are only `1` or `2`, we do not need a priority queue. We can use Dial’s algorithm with `3` buckets indexed by `distance % 3`.

This gives `dist[cell]`, the earliest time Peter can be at each cell center.

Peter may wait at any reachable center.

Complexity:

```text
O(NM)
```

---

### Step 2: Peter may escape directly to the shore

For every reachable cell center, Peter may choose any possible velocity and move until either:

1. he reaches the shore, or
2. he reaches another cell center first.

If the shore is reached before or exactly when the next cell center would be reached, Peter is saved.

For each velocity, compute the time to hit one of the four lake borders. Then minimize:

```text
dist[cell] + time_to_shore
```

---

### Step 3: simulate the boat

The boat has exactly one possible move from every cell: it follows the flow.

Therefore its path is deterministic.

The boat can:

1. stop forever in a zero-flow cell,
2. leave the grid and reach the shore,
3. enter a cycle.

We simulate the boat and record:

```text
bcell[i] = cell occupied at boat time btime[i]
```

If a cell is revisited, the boat is in a cycle.

For a cycle cell, the boat visits it infinitely many times:

```text
base_time + k * period
```

---

### Step 4: Peter meets the boat at a cell center

For every boat-visited cell:

- if it is in the prefix before a cycle, the boat visits it once,
- if it is in the cycle, the boat visits it periodically,
- if the boat stops in a zero-flow cell, it remains there forever.

Peter can meet the boat at that center if he can arrive no later than the boat.

So candidate times are:

- one-time visit: valid if `dist[cell] <= boat_time`,
- cycle visit: first visit time `>= dist[cell]`,
- stationary boat: `max(dist[cell], stop_time)`.

---

### Step 5: Peter meets the boat inside an edge

The boat moves along an edge from cell `A` to adjacent cell `A'` during interval:

```text
[t, t + 1]
```

Since the boat travels only horizontally or vertically, Peter can only meet it inside that edge if Peter also travels along the same edge.

There are two useful cases.

---

#### Case 1: Peter comes head-on from `A'`

Peter starts from the downstream endpoint `A'` and moves toward `A`.

This is possible only if Peter can move from `A'` toward `A` with speed:

- `2`, if the flow at `A'` points toward `A`,
- `1`, if the flow at `A'` is zero.

Let Peter’s earliest arrival at `A'` be `d`.

If his speed is `sp`, meeting time is:

```text
meet = (1 + t + sp * d) / (sp + 1)
```

This is valid only if the meeting point lies inside the edge, which is equivalent to:

```text
t ∈ [d - 1, d + 1 / sp]
```

For cycle edges, choose the first repeated edge time satisfying this interval.

---

#### Case 2: Peter chases the boat from `A`

Peter starts at the same endpoint `A` after the boat has left and swims in the same direction.

This works only if the flow at `A` points in the boat direction, so Peter can swim with speed `2`.

If Peter reaches `A` at time `d`, then he catches the boat at:

```text
meet = 2d - t
```

This is valid when:

```text
d ∈ [t, t + 0.5]
```

Equivalently:

```text
t ∈ [d - 0.5, d]
```

Again, for cycle edges, choose the first edge time satisfying the interval.

---

### Final answer

Take the minimum among:

1. escaping to shore,
2. meeting at a cell center,
3. meeting inside a boat edge.

If no candidate exists, print:

```text
SOS
```

Otherwise print the answer with two digits after the decimal point.

---

## 3. Provided C++ solution with detailed comments

```cpp
#include <bits/stdc++.h>                  // Include all standard C++ headers.

using namespace std;                       // Use the standard namespace.

// Output operator for pairs, useful for debugging/general templates.
template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}

// Input operator for pairs.
template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& x) {
    return in >> x.first >> x.second;
}

// Input operator for vectors.
template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) {                      // Read every element.
        in >> x;
    }
    return in;
};

// Output operator for vectors.
template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto x: a) {                       // Print every element.
        out << x << ' ';
    }
    return out;
};

// Direction vectors indexed by the lake digit.
// 0 = stay, 1 = up, 2 = down, 3 = right, 4 = left.
const int FX[5] = {0, 0, 0, 1, -1};
const int FY[5] = {0, -1, 1, 0, 0};

int n, m;                                  // Lake dimensions.
vector<string> grid;                       // Grid of flow digits.
int peter_x, peter_y, boat_x, boat_y;      // 1-based input coordinates.

// Reads input.
void read() {
    cin >> n >> m;                         // Read dimensions.
    grid.assign(n, "");                    // Allocate grid rows.

    for(int r = 0; r < n; r++) {           // Read every row.
        cin >> grid[r];
    }

    cin >> peter_x >> peter_y >> boat_x >> boat_y; // Read starting positions.
}

void solve() {
    const double INF = 1e18;               // Large value for unreachable times.

    // Checks whether row r, column c is inside the lake.
    auto inside = [&](int r, int c) {
        return r >= 0 && r < n && c >= 0 && c < m;
    };

    // Returns the flow vector of cell (r, c).
    auto flow_of = [&](int r, int c) {
        int d = grid[r][c] - '0';          // Convert char digit to integer.
        return make_pair(FX[d], FY[d]);    // Return corresponding vector.
    };

    // Convert input coordinates from 1-based (x, y) to 0-based (row, col).
    int pr = peter_y - 1, pc = peter_x - 1;
    int br = boat_y - 1, bc = boat_x - 1;

    // dist_half[id] is the shortest Peter time to a cell in half-minutes.
    vector<int> dist_half(n * m, INT_MAX);

    // Dial buckets for edge weights 1 and 2.
    array<vector<int>, 3> bucket;

    // Peter starts at his initial cell at time 0.
    dist_half[pr * m + pc] = 0;
    bucket[0].push_back(pr * m + pc);

    int max_dist = 0;                      // Largest distance currently inserted.

    // Dial's algorithm over increasing half-minute distances.
    for(int d = 0; d <= max_dist; d++) {
        auto& b = bucket[d % 3];           // Current bucket.

        while(!b.empty()) {                // Process all states with this modulo.
            int id = b.back();             // Take a cell id.
            b.pop_back();

            if(dist_half[id] != d) {       // Ignore stale entries.
                continue;
            }

            int r = id / m, c = id % m;    // Decode cell id.

            auto [fx, fy] = flow_of(r, c); // Flow at current cell.

            for(int k = 0; k < 5; k++) {   // Try every Peter swimming vector.
                int vx = fx + FX[k];       // Resulting x velocity.
                int vy = fy + FY[k];       // Resulting y velocity.

                if(vx == 0 && vy == 0) {   // Zero velocity means staying.
                    continue;
                }

                // Direction of movement to the next center.
                int ox = (vx > 0) - (vx < 0);
                int oy = (vy > 0) - (vy < 0);

                int nr = r + oy;           // Next row.
                int nc = c + ox;           // Next column.

                if(!inside(nr, nc)) {      // Ignore moves whose next center is outside.
                    continue;
                }

                // If speed component is 2, time is 0.5 minutes = 1 half-minute.
                // Otherwise time is 1 minute = 2 half-minutes.
                int w = (abs(vx) == 2 || abs(vy) == 2) ? 1 : 2;

                int nd = d + w;            // Candidate new distance.

                if(nd < dist_half[nr * m + nc]) { // Relax edge.
                    dist_half[nr * m + nc] = nd;
                    bucket[nd % 3].push_back(nr * m + nc);
                    max_dist = max(max_dist, nd);
                }
            }
        }
    }

    // Convert half-minute distances to real minutes.
    vector<double> dist(n * m, INF);
    for(int i = 0; i < n * m; i++) {
        if(dist_half[i] != INT_MAX) {
            dist[i] = dist_half[i] * 0.5;
        }
    }

    double ans = INF;                      // Best answer found so far.

    // Try escaping directly to the shore from every reachable center.
    for(int r = 0; r < n; r++) {
        for(int c = 0; c < m; c++) {
            if(dist[r * m + c] >= INF) {   // Skip unreachable cells.
                continue;
            }

            auto [fx, fy] = flow_of(r, c); // Flow at this cell.
            double best_exit = INF;        // Best shore time from this center.

            for(int k = 0; k < 5; k++) {   // Try every swimming vector.
                int vx = fx + FX[k];       // Resulting velocity x.
                int vy = fy + FY[k];       // Resulting velocity y.

                if(vx == 0 && vy == 0) {   // Staying cannot reach shore.
                    continue;
                }

                double tx = INF, ty = INF; // Times to vertical/horizontal borders.

                if(vx > 0) {              // Moving right.
                    tx = ((m - 1) + 0.5 - c) / vx;
                } else if(vx < 0) {       // Moving left.
                    tx = (c + 0.5) / (-vx);
                }

                if(vy > 0) {              // Moving down.
                    ty = ((n - 1) + 0.5 - r) / vy;
                } else if(vy < 0) {       // Moving up.
                    ty = (r + 0.5) / (-vy);
                }

                double t_wall = min(tx, ty); // First border hit.

                // Neighboring center in this movement direction.
                int ox = (vx > 0) - (vx < 0);
                int oy = (vy > 0) - (vy < 0);

                // Time to next center, if such center exists inside lake.
                double t_center =
                    inside(r + oy, c + ox)
                        ? ((abs(vx) == 2 || abs(vy) == 2) ? 0.5 : 1.0)
                        : INF;

                // Shore is usable only if reached before next center.
                if(t_wall <= t_center + 1e-12) {
                    best_exit = min(best_exit, t_wall);
                }
            }

            if(best_exit < INF) {          // Update global answer.
                ans = min(ans, dist[r * m + c] + best_exit);
            }
        }
    }

    // Simulate the boat trajectory.
    vector<int> bcell;                     // Boat cells in order.
    vector<int64_t> btime;                 // Corresponding integer times.
    vector<int> seen_idx(n * m, -1);       // First index where a cell was seen.

    int cr = br, cc = bc;                  // Current boat position.
    int64_t bt = 0;                        // Current boat time.

    int cycle_start = -1;                  // First index of cycle, if any.
    int64_t period = 0;                    // Cycle period.
    bool stationary = false;               // True if boat stops in zero-flow cell.

    while(true) {
        int id = cr * m + cc;              // Current boat cell id.

        if(seen_idx[id] != -1) {           // Found a repeated cell, hence a cycle.
            cycle_start = seen_idx[id];
            period = bt - btime[cycle_start];
            break;
        }

        seen_idx[id] = (int)bcell.size();  // Mark first visit index.
        bcell.push_back(id);               // Store cell.
        btime.push_back(bt);               // Store visit time.

        auto [fx, fy] = flow_of(cr, cc);   // Boat follows only the flow.

        if(fx == 0 && fy == 0) {           // Zero flow: boat stops forever.
            stationary = true;
            break;
        }

        int nr = cr + fy;                  // Next row.
        int nc = cc + fx;                  // Next column.

        if(!inside(nr, nc)) {              // Boat reaches shore and leaves grid.
            break;
        }

        cr = nr;                           // Move boat.
        cc = nc;
        bt++;                              // One minute per cell.
    }

    int len = (int)bcell.size();           // Number of recorded boat cells.

    // Checks whether recorded boat index i belongs to the cycle.
    auto is_cyclic = [&](int i) {
        return cycle_start != -1 && i >= cycle_start;
    };

    // Try meeting the boat at cell centers.
    for(int i = 0; i < len; i++) {
        int id = bcell[i];

        if(dist[id] >= INF) {              // Peter cannot reach this center.
            continue;
        }

        double base = (double)btime[i];    // First visit time of this boat cell.

        if(stationary && i == len - 1) {   // Boat remains here forever.
            ans = min(ans, max(dist[id], base));
        } else if(is_cyclic(i)) {          // Boat revisits this cell periodically.
            double cand = base;

            if(dist[id] > base) {
                // Smallest k such that base + k * period >= dist[id].
                int64_t k =
                    (int64_t)ceil((dist[id] - base) / (double)period - 1e-9);
                cand = base + (double)max(0LL, k) * period;
            }

            ans = min(ans, cand);
        } else {                           // Prefix cell, visited only once.
            if(dist[id] <= base + 1e-9) {
                ans = min(ans, base);
            }
        }
    }

    // Function that tries meeting the boat during one edge traversal.
    auto edge_meet = [&](int a_id, int db_idx, int64_t tb, bool cyc) {
        int ar = a_id / m, ac = a_id % m;  // Boat starts edge from cell A.

        int dx = FX[db_idx], dy = FY[db_idx]; // Boat direction.

        int a2r = ar + dy, a2c = ac + dx;  // Downstream endpoint A'.

        if(!inside(a2r, a2c)) {            // Edge goes out to shore.
            return;
        }

        int a2 = a2r * m + a2c;            // Id of A'.

        // Case 1: Peter comes head-on from A' toward A.
        if(dist[a2] < INF) {
            auto [f2x, f2y] = flow_of(a2r, a2c);

            int sp = 0;                    // Peter speed along edge toward A.

            if(f2x == -dx && f2y == -dy) { // Flow helps Peter toward A.
                sp = 2;
            } else if(f2x == 0 && f2y == 0) { // Still water, Peter swims speed 1.
                sp = 1;
            }

            if(sp > 0) {
                double da = dist[a2];      // Earliest Peter arrival at A'.

                double lo = da - 1.0;      // Earliest valid boat departure time.
                double hi = da + 1.0 / sp; // Latest valid boat departure time.

                double t = (double)tb;     // Boat edge start time.

                if(cyc && t < lo) {        // For cycle edge, advance to first valid repeat.
                    int64_t k = (int64_t)ceil((lo - t) / (double)period - 1e-9);
                    t += (double)max(0LL, k) * period;
                }

                if(t >= lo - 1e-9 && t <= hi + 1e-9) {
                    // Formula for head-on meeting.
                    ans = min(ans, (1.0 + t + sp * da) / (sp + 1));
                }
            }
        }

        // Case 2: Peter chases the boat from A with speed 2.
        if(dist[a_id] < INF) {
            auto [fax, fay] = flow_of(ar, ac);

            if(fax == dx && fay == dy) {   // Flow must point with boat direction.
                double da = dist[a_id];    // Earliest Peter arrival at A.

                double lo = da - 0.5;      // Valid boat edge start interval.
                double hi = da;

                double t = (double)tb;     // Boat edge start time.

                if(cyc && t < lo) {        // Advance cycle edge time if needed.
                    int64_t k = (int64_t)ceil((lo - t) / (double)period - 1e-9);
                    t += (double)max(0LL, k) * period;
                }

                if(t >= lo - 1e-9 && t <= hi + 1e-9) {
                    // Catch-up meeting time.
                    ans = min(ans, 2.0 * da - t);
                }
            }
        }
    };

    // Try all consecutive boat edges in the recorded trajectory.
    for(int i = 0; i + 1 < len; i++) {
        int cellr = bcell[i] / m;
        int cellc = bcell[i] % m;

        int d = grid[cellr][cellc] - '0';  // Boat direction from this cell.

        edge_meet(bcell[i], d, btime[i], is_cyclic(i));
    }

    // If there is a cycle, also process the edge from the last recorded cycle cell
    // back to the cycle entry.
    if(cycle_start != -1) {
        int last = len - 1;

        int cellr = bcell[last] / m;
        int cellc = bcell[last] % m;

        int d = grid[cellr][cellc] - '0';

        edge_meet(bcell[last], d, btime[last], true);
    }

    if(ans >= INF) {                       // No saving method found.
        cout << "SOS\n";
        return;
    }

    // Print minimum time to two digits.
    cout << fixed << setprecision(2) << ans << '\n';
}

int main() {
    ios_base::sync_with_stdio(false);      // Fast I/O.
    cin.tie(nullptr);                      // Untie cin from cout.

    int T = 1;                             // Only one test case.
    // cin >> T;

    for(int test = 1; test <= T; test++) {
        read();                            // Read input.
        solve();                           // Solve test case.
    }

    return 0;                              // Successful termination.
}
```

---

## 4. Python solution with detailed comments

```python
import sys
import math


# Direction arrays indexed by grid digit:
# 0 = still, 1 = up, 2 = down, 3 = right, 4 = left.
FX = [0, 0, 0, 1, -1]
FY = [0, -1, 1, 0, 0]


def solve():
    data = sys.stdin.read().strip().split()

    if not data:
        return

    ptr = 0

    # Read lake dimensions.
    n = int(data[ptr])
    ptr += 1
    m = int(data[ptr])
    ptr += 1

    # Read grid.
    grid = data[ptr:ptr + n]
    ptr += n

    # Peter start, input is 1-based (x, y).
    peter_x = int(data[ptr])
    ptr += 1
    peter_y = int(data[ptr])
    ptr += 1

    # Boat start, input is 1-based (x, y).
    boat_x = int(data[ptr])
    ptr += 1
    boat_y = int(data[ptr])
    ptr += 1

    # Convert to 0-based row/column.
    pr = peter_y - 1
    pc = peter_x - 1
    br = boat_y - 1
    bc = boat_x - 1

    total = n * m
    INF = 10**100

    def inside(r, c):
        """Return True if cell (r, c) is inside the lake."""
        return 0 <= r < n and 0 <= c < m

    def flow_of(r, c):
        """Return flow vector of cell (r, c)."""
        d = ord(grid[r][c]) - ord('0')
        return FX[d], FY[d]

    # ------------------------------------------------------------
    # 1. Shortest times for Peter to reach every cell center.
    # Distances are stored in half-minutes.
    # ------------------------------------------------------------

    BIG = 10**18
    dist_half = [BIG] * total

    start_id = pr * m + pc
    dist_half[start_id] = 0

    # Dial buckets for weights 1 and 2.
    buckets = [[], [], []]
    buckets[0].append(start_id)

    max_dist = 0
    d = 0

    while d <= max_dist:
        bucket = buckets[d % 3]

        while bucket:
            cell_id = bucket.pop()

            # Stale bucket entry.
            if dist_half[cell_id] != d:
                continue

            r = cell_id // m
            c = cell_id % m

            fx, fy = flow_of(r, c)

            # Try all swimming choices.
            for k in range(5):
                vx = fx + FX[k]
                vy = fy + FY[k]

                # Zero velocity means Peter stays at the center.
                if vx == 0 and vy == 0:
                    continue

                # Direction to neighboring center.
                ox = (vx > 0) - (vx < 0)
                oy = (vy > 0) - (vy < 0)

                nr = r + oy
                nc = c + ox

                if not inside(nr, nc):
                    continue

                # Speed 2 means 0.5 minutes, otherwise 1 minute.
                w = 1 if abs(vx) == 2 or abs(vy) == 2 else 2

                nd = d + w
                nid = nr * m + nc

                if nd < dist_half[nid]:
                    dist_half[nid] = nd
                    buckets[nd % 3].append(nid)
                    if nd > max_dist:
                        max_dist = nd

        d += 1

    # Convert half-minutes to minutes.
    dist = [INF] * total
    for i in range(total):
        if dist_half[i] != BIG:
            dist[i] = dist_half[i] * 0.5

    ans = INF

    # ------------------------------------------------------------
    # 2. Try direct escape to the shore.
    # ------------------------------------------------------------

    for r in range(n):
        for c in range(m):
            cell_id = r * m + c

            if dist[cell_id] >= INF:
                continue

            fx, fy = flow_of(r, c)
            best_exit = INF

            for k in range(5):
                vx = fx + FX[k]
                vy = fy + FY[k]

                if vx == 0 and vy == 0:
                    continue

                tx = INF
                ty = INF

                # Time to vertical border.
                if vx > 0:
                    tx = ((m - 1) + 0.5 - c) / vx
                elif vx < 0:
                    tx = (c + 0.5) / (-vx)

                # Time to horizontal border.
                if vy > 0:
                    ty = ((n - 1) + 0.5 - r) / vy
                elif vy < 0:
                    ty = (r + 0.5) / (-vy)

                t_wall = min(tx, ty)

                # Time to next center in that direction.
                ox = (vx > 0) - (vx < 0)
                oy = (vy > 0) - (vy < 0)

                nr = r + oy
                nc = c + ox

                if inside(nr, nc):
                    t_center = 0.5 if abs(vx) == 2 or abs(vy) == 2 else 1.0
                else:
                    t_center = INF

                # Peter reaches shore before needing to recalculate velocity.
                if t_wall <= t_center + 1e-12:
                    best_exit = min(best_exit, t_wall)

            if best_exit < INF:
                ans = min(ans, dist[cell_id] + best_exit)

    # ------------------------------------------------------------
    # 3. Simulate boat path.
    # ------------------------------------------------------------

    bcell = []
    btime = []
    seen = [-1] * total

    cr = br
    cc = bc
    bt = 0

    cycle_start = -1
    period = 0
    stationary = False

    while True:
        cell_id = cr * m + cc

        # Repeated cell means the deterministic path entered a cycle.
        if seen[cell_id] != -1:
            cycle_start = seen[cell_id]
            period = bt - btime[cycle_start]
            break

        seen[cell_id] = len(bcell)
        bcell.append(cell_id)
        btime.append(bt)

        fx, fy = flow_of(cr, cc)

        # Still water: boat remains here forever.
        if fx == 0 and fy == 0:
            stationary = True
            break

        nr = cr + fy
        nc = cc + fx

        # Boat reaches shore and leaves grid.
        if not inside(nr, nc):
            break

        cr = nr
        cc = nc
        bt += 1

    length = len(bcell)

    def is_cyclic(i):
        """Return True if boat record index i belongs to the cycle."""
        return cycle_start != -1 and i >= cycle_start

    # ------------------------------------------------------------
    # 4. Meet boat at cell centers.
    # ------------------------------------------------------------

    for i in range(length):
        cell_id = bcell[i]

        if dist[cell_id] >= INF:
            continue

        base = float(btime[i])

        if stationary and i == length - 1:
            # Boat stays here after base time.
            ans = min(ans, max(dist[cell_id], base))

        elif is_cyclic(i):
            # First cycle visit not earlier than Peter's arrival.
            cand = base

            if dist[cell_id] > base:
                k = math.ceil((dist[cell_id] - base) / period - 1e-9)
                if k < 0:
                    k = 0
                cand = base + k * period

            ans = min(ans, cand)

        else:
            # Prefix cell is visited once.
            if dist[cell_id] <= base + 1e-9:
                ans = min(ans, base)

    # ------------------------------------------------------------
    # 5. Meet boat inside an edge.
    # ------------------------------------------------------------

    def edge_meet(a_id, db_idx, tb, cyc):
        """Try meeting boat while it moves from A to A' at time tb."""
        nonlocal ans

        ar = a_id // m
        ac = a_id % m

        dx = FX[db_idx]
        dy = FY[db_idx]

        a2r = ar + dy
        a2c = ac + dx

        # If boat edge goes out of lake, direct shore escape handles saving.
        if not inside(a2r, a2c):
            return

        a2 = a2r * m + a2c

        # Case 1: Peter comes head-on from A' toward A.
        if dist[a2] < INF:
            f2x, f2y = flow_of(a2r, a2c)

            sp = 0

            # Flow at A' helps Peter move back toward A.
            if f2x == -dx and f2y == -dy:
                sp = 2

            # Still water at A', Peter can swim toward A with speed 1.
            elif f2x == 0 and f2y == 0:
                sp = 1

            if sp > 0:
                da = dist[a2]

                lo = da - 1.0
                hi = da + 1.0 / sp

                t = float(tb)

                # If this is a cycle edge, advance to the first valid repetition.
                if cyc and t < lo:
                    k = math.ceil((lo - t) / period - 1e-9)
                    if k < 0:
                        k = 0
                    t += k * period

                if t >= lo - 1e-9 and t <= hi + 1e-9:
                    meet_time = (1.0 + t + sp * da) / (sp + 1)
                    ans = min(ans, meet_time)

        # Case 2: Peter chases from A in the same direction with speed 2.
        if dist[a_id] < INF:
            fax, fay = flow_of(ar, ac)

            # To have speed 2 in the boat direction, flow must point that way.
            if fax == dx and fay == dy:
                da = dist[a_id]

                lo = da - 0.5
                hi = da

                t = float(tb)

                # For cycle edge, advance to first valid repeated traversal.
                if cyc and t < lo:
                    k = math.ceil((lo - t) / period - 1e-9)
                    if k < 0:
                        k = 0
                    t += k * period

                if t >= lo - 1e-9 and t <= hi + 1e-9:
                    meet_time = 2.0 * da - t
                    ans = min(ans, meet_time)

    # Process all explicit consecutive boat edges.
    for i in range(length - 1):
        cell_id = bcell[i]
        r = cell_id // m
        c = cell_id % m
        dchar = ord(grid[r][c]) - ord('0')

        edge_meet(cell_id, dchar, btime[i], is_cyclic(i))

    # If boat trajectory has a cycle, the last recorded cell also has
    # an edge back into the cycle.
    if cycle_start != -1:
        last = length - 1
        cell_id = bcell[last]
        r = cell_id // m
        c = cell_id % m
        dchar = ord(grid[r][c]) - ord('0')

        edge_meet(cell_id, dchar, btime[last], True)

    # ------------------------------------------------------------
    # Output answer.
    # ------------------------------------------------------------

    if ans >= INF:
        print("SOS")
    else:
        print(f"{ans:.2f}")


if __name__ == "__main__":
    solve()
```

---

## 5. Compressed editorial

Compute Peter’s shortest arrival time to every cell center. His center-to-center travel times are only `0.5` or `1`, so store them as half-minutes with edge weights `1` and `2`. Use Dial’s algorithm with three buckets for `O(NM)`.

For each reachable center, also test whether Peter can move directly to the shore before reaching another center.

Then simulate the boat. Since the boat only follows flow, its path is deterministic: it either stops in zero flow, reaches shore, or enters a cycle.

Try meeting the boat:

1. at centers:
   - once for prefix cells,
   - periodically for cycle cells,
   - forever for a stationary boat;

2. inside edges:
   - Peter comes from the next cell head-on,
   - or Peter starts from the same cell and chases at speed `2`.

For cycle edges, shift the boat edge time forward by multiples of the period until it can satisfy the needed time interval.

Take the minimum valid time. If none exists, output `SOS`; otherwise print the time to two decimals.