Editorial for Nuclear Waste
Submitting an official solution before solving the problem yourself is a bannable offence.
Approach
Solve the problem in three Bellman-Ford-style passes.
Pass 1. Compute how far each location is from the nearest nuclear waste site. Treat the given
directed edges as undirected and run multi-source Bellman-Ford from every waste location. Call this
value .
Pass 2. The safety of a route is the minimum over vertices
on the route. Maximize
safety from
to
with another Bellman-Ford: the state at each node is the best bottleneck so
far, and relaxing
yields
.
Pass 3. Among routes that achieve that maximum safety , maximize total food. Restrict to
nodes with
(any visit below
would drop safety). Run Bellman-Ford maximizing food
on that subgraph.
After food relaxations, the value at node
is optimal among simple routes. Then run
further relaxations and check whether the food at
alone increases. The first of those
iterations updates nodes on a positive-food cycle (if any); up to
more may be needed for
that improvement to reach
. If
's food changes, output
-1.
With and
, the time complexity
is acceptable.
Solution (Python)
import sys
INF = 10**30
NEG_INF = -INF
def main() -> None:
data = list(map(int, sys.stdin.buffer.read().split()))
n, m, w_count = data[0], data[1], data[2]
wastes = [x - 1 for x in data[3 : 3 + w_count]]
idx = 3 + w_count
edges: list[tuple[int, int, int, int]] = []
rev_edges: list[tuple[int, int, int]] = []
for _ in range(m):
fro = data[idx] - 1
to = data[idx + 1] - 1
weight = data[idx + 2]
food = data[idx + 3]
idx += 4
edges.append((fro, to, weight, food))
rev_edges.append((to, fro, weight))
# Pass 1: undirected distance from the nearest waste site.
waste_dist = [INF] * n
for site in wastes:
waste_dist[site] = 0
for _ in range(n - 1):
updated = False
for fro, to, weight, _ in edges:
if waste_dist[fro] == INF:
continue
cand = waste_dist[fro] + weight
if cand < waste_dist[to]:
waste_dist[to] = cand
updated = True
for fro, to, weight in rev_edges:
if waste_dist[fro] == INF:
continue
cand = waste_dist[fro] + weight
if cand < waste_dist[to]:
waste_dist[to] = cand
updated = True
if not updated:
break
# Pass 2: maximum path safety (bottleneck) from 1 to n.
safety = [NEG_INF] * n
safety[0] = waste_dist[0]
for _ in range(n - 1):
updated = False
for fro, to, _, _ in edges:
if safety[fro] == NEG_INF:
continue
cand = min(safety[fro], waste_dist[to])
if cand > safety[to]:
safety[to] = cand
updated = True
if not updated:
break
target_safety = safety[n - 1]
# Pass 3: maximum food among routes that keep safety == target_safety.
# Only visit nodes whose waste distance is at least target_safety.
food = [NEG_INF] * n
if waste_dist[0] >= target_safety:
food[0] = 0
for _ in range(n - 1):
updated = False
for fro, to, _, edge_food in edges:
if food[fro] == NEG_INF or waste_dist[to] < target_safety:
continue
cand = food[fro] + edge_food
if cand > food[to]:
food[to] = cand
updated = True
if not updated:
break
finite_food = food[n - 1]
# One more full n iterations: a positive-food cycle updates on the first of
# these, and up to n-1 further iterations may be needed for that improvement
# to reach node n.
for _ in range(n):
for fro, to, _, edge_food in edges:
if food[fro] == NEG_INF or waste_dist[to] < target_safety:
continue
cand = food[fro] + edge_food
if cand > food[to]:
food[to] = cand
ans_food = food[n - 1]
if ans_food != finite_food:
ans_food = -1
print(target_safety, ans_food)
if __name__ == "__main__":
main()
Comments