Approach: treat latency as a constrained resource and maximize multiplicative reliability (product of edge probabilities). Take log to convert product → sum of logs (maximize sum of logs). Use a stateful Dijkstra/DP where state is (node, used_latency). For pseudo-polynomial L (integer latencies), maintain best log-reliability seen for each (node, t) and use a max-priority queue over log-reliability. This is like knapsack+shortest-path.python
import heapq
import math
from collections import defaultdict
def max_reliability_with_latency(graph, src, dst, L):
"""
graph: dict[u] = list of (v, latency:int, reliability:float)
latencies assumed integer and non-negative
Returns: (best_reliability, path) where best_reliability in [0,1]
"""
# dp[node][t] = max log-reliability achievable reaching node with total latency t
dp = defaultdict(lambda: dict())
# parent for path reconstruction: parent[(node,t)] = (prev_node, prev_t)
parent = {}
# max-heap by log-reliability (use negative for heapq)
pq = []
dp[src][0] = 0.0 # log(1)=0
heapq.heappush(pq, (-0.0, src, 0))
while pq:
neg_logr, u, t = heapq.heappop(pq)
logr = -neg_logr
# skip stale
if dp[u].get(t, -math.inf) != logr:
continue
if u == dst:
# we could continue to find potentially better at other latencies <= L
pass
for v, lat, rel in graph.get(u, ()):
nt = t + lat
if nt > L:
continue
if rel <= 0:
continue
nlog = logr + math.log(rel)
if nlog > dp[v].get(nt, -math.inf):
dp[v][nt] = nlog
parent[(v, nt)] = (u, t)
heapq.heappush(pq, (-nlog, v, nt))
# find best at dst over all t<=L
best_t, best_log = None, -math.inf
for t, logr in dp.get(dst, {}).items():
if logr > best_log:
best_log = logr
best_t = t
if best_t is None:
return 0.0, [] # no feasible path
# reconstruct path
path = []
cur = (dst, best_t)
while cur[0] != src or cur[1] != 0:
node, tt = cur
path.append(node)
cur = parent.get(cur)
if cur is None:
break
path.append(src)
path.reverse()
return math.exp(best_log), path
Key points:- Using log turns multiplication into addition and avoids underflow.- State is (node, total_latency) — keep best log-reliability per state.- Priority queue explores better reliability states first; complexity O(E * L * log(E*L)) roughly.Edge cases:- Zero reliability edges (skip), zero latencies, unreachable target.Alternatives:- If latencies are large floats, discretize or switch to Lagrangian relaxation (maximize logr - lambda * latency) and binary search lambda.