## 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. C++ Solution

```cpp
#include <bits/stdc++.h>

using namespace std;

template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}

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

template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) {
        in >> x;
    }
    return in;
};

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto x: a) {
        out << x << ' ';
    }
    return out;
};

const int FX[5] = {0, 0, 0, 1, -1};
const int FY[5] = {0, -1, 1, 0, 0};

int n, m;
vector<string> grid;
int peter_x, peter_y, boat_x, boat_y;

void read() {
    cin >> n >> m;
    grid.assign(n, "");
    for(int r = 0; r < n; r++) {
        cin >> grid[r];
    }

    cin >> peter_x >> peter_y >> boat_x >> boat_y;
}

void solve() {
    // Cell (col c, row r) has its centre at the point (c, r); the lake occupies
    // x in [-0.5, m-0.5], y in [-0.5, n-0.5]. The flow digit picks one of five
    // vectors and Peter adds one of the same five, so a resulting velocity has
    // each component in {-2,-1,0,1,2}: along the flow axis he moves at speed 2
    // (next centre in 0.5 min), at speed 1 with no push (1 min), diagonally at
    // speed sqrt(2) to a diagonal neighbour (1 min), or stays put by cancelling
    // the flow. Every Peter-to-centre time is therefore a multiple of 0.5, so a
    // shortest path with edge weights 1 and 2 in half-minutes gives dist[c],
    // the earliest he can sit in each centre (he may then wait there
    // arbitrarily). Because the weights are only 1 and 2 the live frontier
    // spans at most three consecutive distances, so Dial's algorithm with
    // buckets keyed by distance % 3 settles every cell in order without a heap.
    //
    // The boat only drifts, so from any cell it has a single successor: it
    // steps one axis-aligned cell per minute. A deterministic walk with one
    // successor each must, within at most n*m steps, either stop on a
    // still-water cell, step off the board through the shore, or revisit a cell
    // it has already seen. The first repeated cell is where the trajectory
    // folds into a cycle: the prefix before it is walked once, and from there
    // the boat loops forever with period = (current time) - (time the repeated
    // cell was first seen). So a prefix cell is occupied at one fixed time,
    // while a cycle cell is occupied at base + k*period for every k >= 0; the
    // move from the last recorded cell back to the cycle's entry is itself an
    // edge of the loop and is added explicitly. Reaching the shore is always a
    // save, so one candidate answer is the min over cells of dist[c] plus the
    // time to push out of the nearest wall from c (half the usual cell-crossing
    // time, since a wall sits half a cell from the centre).
    //
    // To meet the boat there are three ways, each turned into the earliest
    // valid time and minimised together with the shore candidate. First, Peter
    // can sit in a centre the boat visits: he is fine as long as he arrives no
    // later than the boat, so the candidate is the earliest visit time >=
    // dist[c] (just the single time for a prefix cell, or base + k*period
    // rounded up past dist[c] for a cycle cell, or max(dist[c], stop_time) for
    // a stalled boat).
    //
    // Second, while the boat crosses an edge from A to A' during [t, t+1] Peter
    // can dart in from A' straight back toward A, head-on against it. To stay
    // on the edge his velocity must lie along it, so his speed sp there is 2 if
    // the flow at A' points from A' to A, 1 if A' is still water, and otherwise
    // this case does not apply. Leaving A' at his earliest time dist[A'] and
    // meeting the boat after he has covered sp*(t_m - dist[A']) while the boat
    // has covered (t_m - t) of the unit edge gives sp*(t_m - dist[A']) = 1 -
    // (t_m - t), i.e. t_m = (1 + t + sp*dist[A']) / (sp + 1). This only counts
    // when the contact point really falls inside the edge, which works out to t
    // lying in [dist[A'] - 1, dist[A'] + 1/sp]; for a cycle edge the smallest
    // qualifying t = base + k*period is used (this is the case the 2/3 sample
    // needs).
    //
    // Third, Peter can chase the boat from A in its own direction at speed 2
    // (only when the flow at A matches the boat's heading). Closing the unit
    // gap at relative speed 2 - 1 gives t_m = 2*dist[A] - t, valid when dist[A]
    // lies in [t, t + 0.5] (earlier arrival is just the centre-wait case at A).
    // If no candidate is ever finite Peter cannot be saved and the answer is
    // SOS.

    const double INF = 1e18;

    auto inside = [&](int r, int c) {
        return r >= 0 && r < n && c >= 0 && c < m;
    };

    auto flow_of = [&](int r, int c) {
        int d = grid[r][c] - '0';
        return make_pair(FX[d], FY[d]);
    };

    vector<int> dist_half(n * m, INT_MAX);
    int pr = peter_y - 1, pc = peter_x - 1;
    int br = boat_y - 1, bc = boat_x - 1;

    array<vector<int>, 3> bucket;
    dist_half[pr * m + pc] = 0;
    bucket[0].push_back(pr * m + pc);

    int max_dist = 0;
    for(int d = 0; d <= max_dist; d++) {
        auto& b = bucket[d % 3];
        while(!b.empty()) {
            int id = b.back();
            b.pop_back();
            if(dist_half[id] != d) {
                continue;
            }

            int r = id / m, c = id % m;
            auto [fx, fy] = flow_of(r, c);
            for(int k = 0; k < 5; k++) {
                int vx = fx + FX[k], vy = fy + FY[k];
                if(vx == 0 && vy == 0) {
                    continue;
                }

                int ox = (vx > 0) - (vx < 0), oy = (vy > 0) - (vy < 0);
                int nr = r + oy, nc = c + ox;
                if(!inside(nr, nc)) {
                    continue;
                }

                int w = (abs(vx) == 2 || abs(vy) == 2) ? 1 : 2;
                int nd = d + w;
                if(nd < dist_half[nr * m + nc]) {
                    dist_half[nr * m + nc] = nd;
                    bucket[nd % 3].push_back(nr * m + nc);
                    max_dist = max(max_dist, nd);
                }
            }
        }
    }

    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;

    for(int r = 0; r < n; r++) {
        for(int c = 0; c < m; c++) {
            if(dist[r * m + c] >= INF) {
                continue;
            }

            auto [fx, fy] = flow_of(r, c);
            double best_exit = INF;
            for(int k = 0; k < 5; k++) {
                int vx = fx + FX[k], vy = fy + FY[k];
                if(vx == 0 && vy == 0) {
                    continue;
                }

                double tx = INF, ty = INF;
                if(vx > 0) {
                    tx = ((m - 1) + 0.5 - c) / vx;
                } else if(vx < 0) {
                    tx = (c + 0.5) / (-vx);
                }
                if(vy > 0) {
                    ty = ((n - 1) + 0.5 - r) / vy;
                } else if(vy < 0) {
                    ty = (r + 0.5) / (-vy);
                }

                double t_wall = min(tx, ty);
                int ox = (vx > 0) - (vx < 0), oy = (vy > 0) - (vy < 0);
                double t_center =
                    inside(r + oy, c + ox)
                        ? ((abs(vx) == 2 || abs(vy) == 2) ? 0.5 : 1.0)
                        : INF;
                if(t_wall <= t_center + 1e-12) {
                    best_exit = min(best_exit, t_wall);
                }
            }

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

    vector<int> bcell;
    vector<int64_t> btime;
    vector<int> seen_idx(n * m, -1);
    int cr = br, cc = bc;
    int64_t bt = 0;
    int cycle_start = -1;
    int64_t period = 0;
    bool stationary = false;

    while(true) {
        int id = cr * m + cc;
        if(seen_idx[id] != -1) {
            cycle_start = seen_idx[id];
            period = bt - btime[cycle_start];
            break;
        }

        seen_idx[id] = (int)bcell.size();
        bcell.push_back(id);
        btime.push_back(bt);

        auto [fx, fy] = flow_of(cr, cc);
        if(fx == 0 && fy == 0) {
            stationary = true;
            break;
        }

        int nr = cr + fy, nc = cc + fx;
        if(!inside(nr, nc)) {
            break;
        }

        cr = nr;
        cc = nc;
        bt++;
    }

    int len = (int)bcell.size();
    auto is_cyclic = [&](int i) {
        return cycle_start != -1 && i >= cycle_start;
    };

    for(int i = 0; i < len; i++) {
        int id = bcell[i];
        if(dist[id] >= INF) {
            continue;
        }

        double base = (double)btime[i];
        if(stationary && i == len - 1) {
            ans = min(ans, max(dist[id], base));
        } else if(is_cyclic(i)) {
            double cand = base;
            if(dist[id] > base) {
                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 {
            if(dist[id] <= base + 1e-9) {
                ans = min(ans, base);
            }
        }
    }

    auto edge_meet = [&](int a_id, int db_idx, int64_t tb, bool cyc) {
        int ar = a_id / m, ac = a_id % m;
        int dx = FX[db_idx], dy = FY[db_idx];
        int a2r = ar + dy, a2c = ac + dx;
        if(!inside(a2r, a2c)) {
            return;
        }
        int a2 = a2r * m + a2c;

        if(dist[a2] < INF) {
            auto [f2x, f2y] = flow_of(a2r, a2c);
            int sp = 0;
            if(f2x == -dx && f2y == -dy) {
                sp = 2;
            } else if(f2x == 0 && f2y == 0) {
                sp = 1;
            }

            if(sp > 0) {
                double da = dist[a2];
                double lo = da - 1.0, hi = da + 1.0 / sp;
                double t = (double)tb;
                if(cyc && t < lo) {
                    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) {
                    ans = min(ans, (1.0 + t + sp * da) / (sp + 1));
                }
            }
        }

        if(dist[a_id] < INF) {
            auto [fax, fay] = flow_of(ar, ac);
            if(fax == dx && fay == dy) {
                double da = dist[a_id];
                double lo = da - 0.5, hi = da;
                double t = (double)tb;
                if(cyc && t < lo) {
                    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) {
                    ans = min(ans, 2.0 * da - t);
                }
            }
        }
    };

    for(int i = 0; i + 1 < len; i++) {
        int cellr = bcell[i] / m, cellc = bcell[i] % m;
        int d = grid[cellr][cellc] - '0';
        edge_meet(bcell[i], d, btime[i], is_cyclic(i));
    }

    if(cycle_start != -1) {
        int last = len - 1;
        int cellr = bcell[last] / m, cellc = bcell[last] % m;
        int d = grid[cellr][cellc] - '0';
        edge_meet(bcell[last], d, btime[last], true);
    }

    if(ans >= INF) {
        cout << "SOS\n";
        return;
    }

    cout << fixed << setprecision(2) << ans << '\n';
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int T = 1;
    // cin >> T;
    for(int test = 1; test <= T; test++) {
        read();
        solve();
    }

    return 0;
}
```

---

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