Zak
Zak

Reputation: 13

Load Balancing of values into 8 "silos"

I've got a problem I can't seem to crack. It's not that easy to explain so I'll do my best :

I have a really big array of values I have already sorted :

[ 2, 8, 26, ..., 1456, 1879, ..., 7812, 9614, ..., 20 408, 26 584 ]

I have 8 empty "silos" (kind of like an array) with unlimited capacity.

My goal is to fill those silo with all my values in order to make them as balanced as possible. When I say "balanced", I mean that I want the sum of all the values in a silo to be almost equal to one another.

For example, if my silo 1 has a total sum of 52 000 and my silo 8 has a sum of 30 000 then it's not good. I'd rather have something like 41 000 and 43 500 if possible.

I've already done a round Robin, but it doesn't seem precise enough because I get a quite big difference between my silos. I've looked up bin-packing also but it doesn't seem appropriate to me.

Thank you for any help or advice you may provide!

Upvotes: 1

Views: 200

Answers (1)

Manfred Radlwimmer
Manfred Radlwimmer

Reputation: 13394

Optimization problems are never easy, but since you want to minimize the deviation from the average you simply iterate your values from highest to lowest value and add it to the silo with the lowest sum. That way you don't waste too much time on optimization and should (depending on your values) have a relatively good result.

// Generate some random data
int[] values = new int[1000];

Random r = new Random();

for (int i = 0; i < values.Length; i++)
{
    values[i] = r.Next(1, 30000);
}

// Initialize silos
const int siloCount = 8;
List<int>[] result = new List<int>[siloCount];
for (int i = 0; i < siloCount; i++)
{
    result[i] = new List<int>();
}

int[] sums = new int[siloCount];
int[] indices = Enumerable.Range(0, siloCount).ToArray();

// Iterate all values in descending order
foreach (int value in values.OrderByDescending(i => i).ToList())
{
    // Find silo with lowest sum (or one of them)
    int siloIndex = indices.First(i => sums[i] == sums.Min());

    // Add to collection and sum - so we don't have to call .Sum() every iteration
    sums[siloIndex] += value;
    result[siloIndex].Add(value);
}

Debug.WriteLine(String.Join("\r\n", result.Select(s => s.Sum())));

.Net Fiddle

Upvotes: 2

Related Questions