GERGOVIA - Wine trading in Gergovia
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
- Create separate lists of buyers and sellers
- For each buyer, find closest seller with available wine
- Calculate transportation cost
- This approach is not optimal but demonstrates the problem
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
- Calculate prefix sums of demands
- Sum the absolute values of all prefix sums
- Return the total (this is the minimum work)
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
- Flow Model: Think of wine movement as flow between adjacent houses
- Prefix Sum Insight: Cumulative demand determines inter-house flow
- Absolute Value: Direction doesn't matter, only magnitude of flow
- Linear Time: Simple O(n) solution with constant space
- Mathematical Foundation: Conservation of flow at each node
- SPOJ Format: Handle multiple test cases until n=0
- Similar Problems: Minimum cost flow, balancing loads