公式

D - もこもこクラウドホッピング / Fluffy Cloud Hopping 解説 by admin

gpt-5.3-codex

Overview

This is a shortest path problem where the state includes the “current fluffiness level.”
Instead of only vertices, we treat (cloud, current fluffiness) as a single state, rebuild the graph accordingly, and find the shortest time using Dijkstra’s algorithm.

Analysis

The difficulty of this problem lies in the fact that the movement cost depends on the “current fluffiness level you have.”
In other words, even if you are at the same cloud \(u\), if your current fluffiness \(f\) is different, the next movement cost will change.


First, a common mistake is to only maintain

  • dist[u] = shortest time to cloud u

and run a standard shortest path algorithm, which results in WA.
This is because even if you arrive at cloud \(u\) “a little later,” if your fluffiness at that time is smaller, subsequent movements become cheaper, and you may ultimately reach the goal faster.


The key insight is as follows:

  • Define the state as \((u, f)\) (at cloud \(u\) with current fluffiness \(f\))
  • Solve the shortest path in this state space

There are two types of transitions:

  1. Adoption transition (change in place)
    Upon arriving at cloud \(u\), you can change your fluffiness to \(F_u\).
    This is a transition with cost \(0\): $\( (u, f) \to (u, F_u) \)$

  2. Movement transition (traversing an edge)
    Traversing edge \((u,v,t)\) with current fluffiness \(f\) gives: $\( (u, f) \to (v, f),\quad \text{cost}=t \times f \)\( (In the implementation, \)f\( is 0-indexed, so the actual cost is \)t \times (f+1)$)

This results in a “shortest path with non-negative weights,” so Dijkstra’s algorithm can be applied directly.
Since the constraint \(K \le 5\) is small, the number of states \(N \times K\) is perfectly feasible.

Algorithm

  1. Convert fluffiness \(F_i\) to 0-indexed (\(1..K \to 0..K-1\)).
  2. Initialize dist[u][f] as “shortest time to state \((u,f)\).”
  3. The initial state is being at cloud 1 with fluffiness \(F_1\), so
    dist[0][F[0]] = 0.
  4. Run Dijkstra with a priority queue:
    • From the extracted state \((u,f)\):
      • Adoption transition: \((u,f) \to (u,F_u)\) (cost 0)
      • For each adjacent edge \((u,v,t)\), movement transition: \((u,f)\to(v,f)\) (cost \(t \times (f+1)\))
    • Push if an improvement is found
  5. The answer is min(dist[N-1][f]) over all \(f\). Output -1 if unreachable.

Complexity

  • Number of states: \(N \times K\)
  • Transitions from each state: 1 adoption + number of adjacent edges
    Overall, roughly \(O((NK + MK)\log(NK))\)

Therefore: - Time complexity: \(O((N K + M K)\log(NK))\) - Space complexity: \(O(NK + MK)\) (for dist and the equivalent state graph. The adjacency list itself in the implementation is \(O(N+M)\))

Implementation Notes

  • Using 0-indexed fluffiness simplifies array management (multiply movement cost by f+1).

  • As a standard Dijkstra technique, use if d != dist[u][f]: continue to discard stale queue entries.

  • Edge weights can be up to \(10^9 \times 5\), and path lengths can also become very large, so handle them safely with Python’s int (e.g., set INF = 10**30 or some sufficiently large value).

    Source Code

import sys
import heapq

def main():
    input = sys.stdin.readline
    N, M, K = map(int, input().split())
    F = list(map(int, input().split()))
    F = [x - 1 for x in F]  # 0-indexed fluffiness

    g = [[] for _ in range(N)]
    for _ in range(M):
        u, v, t = map(int, input().split())
        u -= 1
        v -= 1
        g[u].append((v, t))
        g[v].append((u, t))

    INF = 10**30
    # dist[node][f] = min time to be at node with current fluffiness f (0..K-1)
    dist = [[INF] * K for _ in range(N)]

    start_f = F[0]
    dist[0][start_f] = 0
    pq = [(0, 0, start_f)]  # (cost, node, fluff)

    while pq:
        d, u, f = heapq.heappop(pq)
        if d != dist[u][f]:
            continue

        # Option: adopt this cloud's fluffiness
        fu = F[u]
        if d < dist[u][fu]:
            dist[u][fu] = d
            heapq.heappush(pq, (d, u, fu))

        # Move along edges with current fluffiness f
        mult = f + 1
        for v, t in g[u]:
            nd = d + t * mult
            if nd < dist[v][f]:
                dist[v][f] = nd
                heapq.heappush(pq, (nd, v, f))

    ans = min(dist[N - 1])
    print(ans if ans < INF else -1)

if __name__ == "__main__":
    main()

This editorial was generated by gpt-5.3-codex.