Is There a Bargain Loop That Pays You Forever

Solve this Problem
Medium25–30 min
Topics
Companies

A network of trading posts has one-way trades, each with a cost (negative means you earn money). Decide whether the network contains a bargain loop: a cycle of trades that brings you back to the starting post with a negative total cost, so that repeating it earns money forever.

Bellman-Ford's relaxation rounds settle down after n − 1 rounds unless a negative cycle exists, which gives a simple test.

Test Case 1:

Input:cost = [[100,2,100,100,100],[100,100,-4,100,100],[100,100,100,1,100],[100,1,100,100,3],[100,100,100,100,100]]
Output:true
Explanation:Adjacency-list view: 0:[(1,2)], 1:[(2,-4)], 2:[(3,1)], 3:[(1,1),(4,3)]. The loop 1 → 2 → 3 → 1 costs −4 + 1 + 1 = −2 each time round.

Test Case 2:

Input:cost = [[100,3],[-2,100]]
Output:false
Explanation:The loop 0 → 1 → 0 costs 3 − 2 = 1 > 0: going round costs money.

Test Case 3:

Input:cost = [[-1]]
Output:true
Explanation:A trade from the post to itself that pays 1 is itself a negative loop.

Constraints

  • ◆1 ≤ n ≤ 7 trading posts numbered 0 … n-1; cost is an n × n matrix: cost[u][v] = 100 means no one-way trade from u to v, otherwise cost[u][v] (−9 … 9, zero allowed) is what you pay for the trade (negative means you gain money)
  • ◆A trade from a post to itself is allowed (cost[u][u] may be a real value)
  • ◆A bargain loop is a cycle of trades (returning to the starting post) whose total cost is negative; the loop may be anywhere in the network, not necessarily connected to a particular start
  • ◆Return true if the network contains a bargain loop, otherwise false
🚀

Try the Dry Run

Don't just read the solution — watch it execute, one step at a time.

Approach & Solutions

Brute Force — Search Every Cycle and Add Up Its Cost

Brute

A bargain loop can always be chosen to visit each post only once, so search every cycle: from each starting post, follow the trades in a depth-first search that never visits a post twice, adding up the costs, and whenever a trade leads back to the starting post check whether the total cost is negative. This tries a huge number of cycles when the network is dense.

TimeO(n · n!)
SpaceO(n)
1class Solution { 2 private boolean walk(int[][] cost, int start, int u, int total, boolean[] onPath) { 3 onPath[u] = true; 4 for (int v = 0; v < cost.length; v++) { 5 int c = cost[u][v]; 6 if (c == 100) continue; 7 if (v == start) { 8 if (total + c < 0) return true; 9 } else if (!onPath[v] && walk(cost, start, v, total + c, onPath)) { 10 return true; 11 } 12 } 13 onPath[u] = false; 14 return false; 15 } 16 17 public boolean hasBargainLoop(int[][] cost) { 18 for (int start = 0; start < cost.length; start++) { 19 if (walk(cost, start, start, 0, new boolean[cost.length])) return true; 20 } 21 return false; 22 } 23}

Optimal — Bellman-Ford Started From Every Post at Once

Optimal

Give every post the starting value 0, as if a hidden post had a free trade to each of them; then negative loops anywhere in the network are reachable. Repeat rounds in which every trade (u, v) tries to lower dist[v] to dist[u] + cost. Without a negative loop the values stop changing after at most n − 1 rounds, so a round without any change means "no loop". If the values still change in every one of n rounds, a negative loop keeps lowering them forever.

TimeO(n³) with a matrix (O(n · E) with lists)
SpaceO(n)
1class Solution { 2 public boolean hasBargainLoop(int[][] cost) { 3 int n = cost.length; 4 int[] dist = new int[n]; 5 for (int round = 0; round < n; round++) { 6 boolean relaxed = false; 7 for (int u = 0; u < n; u++) { 8 for (int v = 0; v < n; v++) { 9 if (cost[u][v] != 100 && dist[u] + cost[u][v] < dist[v]) { 10 dist[v] = dist[u] + cost[u][v]; 11 relaxed = true; 12 } 13 } 14 } 15 if (!relaxed) return false; 16 } 17 return true; 18 } 19}

Related Problems