Editorial for Nuclear Waste
Submitting an official solution before solving the problem yourself is a bannable offence.
Approach
First compute how far each location is from the nearest nuclear waste site. Treat the given
directed edges as undirected for this step and run Bellman-Ford (or any multi-source shortest-path
algorithm) from every waste location. Call this value .
The safety of a route is the minimum over vertices
on the route. Maximize safety;
among routes with the same safety, maximize total food.
Run another Bellman-Ford-style relaxation on the directed graph, where the state at each node is
the lexicographic pair . Relaxing edge
with food
produces the
candidate pair with safety
and food
. Keep the better
pair at each node.
After relaxations, the food value at node
is finite if no improving cycle remains.
Running
further relaxations and checking whether the food at
increases detects a
positive-food cycle that preserves the optimal safety; in that case output
-1 for food.
With and
, the time complexity
is acceptable.
Solution (Python)
import sys
INF = 10**30
NEG_INF = -INF
def better(a: tuple[int, int], b: tuple[int, int]) -> bool:
if a[0] != b[0]:
return a[0] > b[0]
return a[1] > b[1]
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))
# Undirected distances 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
# Maximize (path safety, food), where safety is the minimum waste_dist on the path.
best = [(NEG_INF, NEG_INF) for _ in range(n)]
best[0] = (waste_dist[0], 0)
for _ in range(n - 1):
updated = False
for fro, to, weight, food in edges:
if best[fro][0] == NEG_INF:
continue
cand = (min(waste_dist[to], best[fro][0]), best[fro][1] + food)
if better(cand, best[to]):
best[to] = cand
updated = True
if not updated:
break
finite_food = best[n - 1][1]
for _ in range(n - 1):
updated = False
for fro, to, weight, food in edges:
if best[fro][0] == NEG_INF:
continue
cand = (min(waste_dist[to], best[fro][0]), best[fro][1] + food)
if better(cand, best[to]):
best[to] = cand
updated = True
if not updated:
break
safety, food = best[n - 1]
if food != finite_food:
food = -1
print(safety, food)
if __name__ == "__main__":
main()
Comments