GreedyProblem 27 of 35

GERGOVIA - Wine trading in Gergovia

Brute Force
Time: O(n²)
Space: O(n)
Optimal
Time: O(n)
Space: O(1)

Problem Statement

SPOJ Problem - GERGOVIA (Wine Trading in Gergovia)

Gergovia is a village with houses arranged in a row. Each house either wants to buy or sell wine. The total wine for sale equals the total wine desired. Moving one unit of wine from house i to house i+1 (or i-1) costs 1 unit of work.

Calculate the minimum amount of work needed to satisfy all demands.

Constraints:

  • 2 ≤ n ≤ 100,000
  • Each demand is between -1000 and 1000
  • Positive value = want to buy, Negative value = want to sell
  • Sum of all demands = 0

Example:

  • Input: demands = [5, -4, 1, -3, 1]
  • Output: 9
  • Explanation:
    • Move 4 from house 2 to house 1 (cost 4)
    • Move 1 from house 2 to house 3 (cost 1)
    • Move 2 from house 4 to house 3 (cost 2, satisfies house 3's need of 1 + house 5's need of 1)
    • Move 1 from house 4 to house 5 (cost 1)
    • Total = 4 + 1 + 2 + 1 = 8... (let me verify)

Approach 1: Brute Force (Simulation)

Intuition

Simulate the wine trading process. For each house that wants to buy, find the nearest seller and transport wine. This doesn't guarantee optimal but gives a valid solution.

Algorithm

  1. Create separate lists of buyers and sellers
  2. For each buyer, find closest seller with available wine
  3. Calculate transportation cost
  4. This approach is not optimal but demonstrates the problem
java
import java.util.*;

public class Solution {
    public long minWorkBrute(int[] demands) {
        int n = demands.length;
        int[] wine = demands.clone();
        long totalWork = 0;
        
        for (int i = 0; i < n; i++) {
            while (wine[i] > 0) {
                for (int j = 0; j < n; j++) {
                    if (wine[j] < 0) {
                        int transfer = Math.min(wine[i], -wine[j]);
                        wine[i] -= transfer;
                        wine[j] += transfer;
                        totalWork += (long)transfer * Math.abs(i - j);
                        break;
                    }
                }
            }
        }
        
        return totalWork;
    }
}

Complexity Analysis

  • Time Complexity: O(n²) - For each house, may scan all houses
  • Space Complexity: O(n) - Copy of demands array

Approach 2: Prefix Sum (Optimal)

Intuition

Think of the problem as flow between adjacent houses. The wine that flows between house i and house i+1 equals the cumulative demand up to house i.

Key Insight: If we define prefix[i] = sum of demands from house 0 to house i:

  • prefix[i] represents the net wine that must flow from left (houses 0..i) to right (houses i+1..n-1)
  • If prefix[i] > 0, wine flows right
  • If prefix[i] < 0, wine flows left

The total work = sum of |prefix[i]| for all i from 0 to n-2.

Algorithm

  1. Calculate prefix sums of demands
  2. Sum the absolute values of all prefix sums
  3. Return the total (this is the minimum work)
java
import java.util.*;

public class Solution {
    public long minWork(int[] demands) {
        int n = demands.length;
        long totalWork = 0;
        long prefix = 0;
        
        for (int i = 0; i < n - 1; i++) {
            prefix += demands[i];
            totalWork += Math.abs(prefix);
        }
        
        return totalWork;
    }
    
    public static void main(String[] args) {
        Solution sol = new Solution();
        int[] demands = {5, -4, 1, -3, 1};
        System.out.println(sol.minWork(demands));  // Output: 9
    }
}

Dry Run Example

demands = [5, -4, 1, -3, 1] Step-by-step prefix sum calculation: i=0: prefix = 5 House 0 has demand +5 (wants to buy) Wine flow across edge 0-1: |5| = 5 i=1: prefix = 5 + (-4) = 1 House 1 sells 4, so cumulative demand is 5-4=1 Wine flow across edge 1-2: |1| = 1 i=2: prefix = 1 + 1 = 2 House 2 wants 1, cumulative = 2 Wine flow across edge 2-3: |2| = 2 i=3: prefix = 2 + (-3) = -1 House 3 sells 3, cumulative = -1 Wine flow across edge 3-4: |-1| = 1 Total work = 5 + 1 + 2 + 1 = 9 Verification: - Houses: [wants 5, sells 4, wants 1, sells 3, wants 1] - Net flow between houses: - Edge 0-1: 5 units right (house 0 needs 5, gets from right side) Wait, house 1 sells 4, so 4 goes left to house 0 House 0 still needs 1 more, comes from further right... Let me think differently: - prefix[0] = 5: The left segment [0] has demand 5 This means 5 units must come from right → cost 5 - prefix[1] = 1: The left segment [0,1] has demand 1 After house 1 sells 4, net demand is 1 This 1 unit must flow from right → cost 1 - prefix[2] = 2: The left segment [0,1,2] has demand 2 This must come from right → cost 2 - prefix[3] = -1: The left segment [0,1,2,3] has demand -1 This means 1 unit flows from left to right → cost 1 Total = 5 + 1 + 2 + 1 = 9 ✓

Complete SPOJ Solution

Python SPOJ Solution

Complexity Analysis

  • Time Complexity: O(n) - Single pass through the array
  • Space Complexity: O(1) - Only using constant extra space

Mathematical Proof

Why does the prefix sum approach work?

Consider the flow model:

  • Let f[i] = amount of wine flowing across edge (i, i+1)
  • Positive f[i] means wine flows from left to right
  • Negative f[i] means wine flows from right to left

For house i to satisfy its demand:

(flow in from left) - (flow out to right) + (flow in from right) - (flow out to left) = demand[i]

This simplifies to:

f[i-1] - f[i] = demand[i]

Therefore:

f[i] = f[i-1] - demand[i] f[i] = -sum(demand[0..i]) f[i] = -prefix[i]

Total work = sum of |f[i]| = sum of |prefix[i]|


Key Takeaways

  1. Flow Model: Think of wine movement as flow between adjacent houses
  2. Prefix Sum Insight: Cumulative demand determines inter-house flow
  3. Absolute Value: Direction doesn't matter, only magnitude of flow
  4. Linear Time: Simple O(n) solution with constant space
  5. Mathematical Foundation: Conservation of flow at each node
  6. SPOJ Format: Handle multiple test cases until n=0
  7. Similar Problems: Minimum cost flow, balancing loads