我正在寻找一种算法,将不同大小的项目列表拆分为“N”个类似大小的组。
具体来说,我正在使用C#中的ASP.NET站点,我有一个(数据库检索的)字符串列表。琴弦的长度各不相同。我有一组需要显示字符串的列。我需要一种算法来找到最平衡的集合(项目顺序无关紧要),以使最终的列尽可能平衡。
创建3列。
要分发的物品:
- Item A - height 5
- Item B - height 3
- Item C - height 7
- Item D - height 2
- Item E - height 3
期望的输出:
Column 1: Item A, Item D
Column 2: Item C
Column 3: Item B, Item E
答案 0 :(得分:3)
最快的事情可能就是将每个新项目插入最小的列表中(其中“最小”是列表中所有项目大小的总和)。
答案 1 :(得分:1)
这似乎是包装盒(或装箱包装)问题的变体,您可以尝试将可变大小的物品集合装入尽可能少的容器中:
http://en.wikipedia.org/wiki/Bin_packing_problem
根据您的项目大小,您可能会相当简单地强制解决方案,寻找具有最小尺寸差异的组合。对于较大的集合,这变得非常困难,使用“简单”算法可能会让您更接近一个好的答案。
答案 2 :(得分:1)
看看job shop scheduling algorithms我们有多个不同大小的工作要在机器上分配,以便总生产时间最短。
答案 3 :(得分:1)
这是另一个可以创建所需长度组的版本。
public static List<List<int>> Balance(List<int> input, int desiredLimit)
{
var result = new List<List<int>>();
if (input.Count > 0)
{
var values = new List<int>(input);
values.Sort();
var start = 0;
var end = values.Count - 1;
var orderedValues = new List<int>(values.Count);
while (start < end)
{
orderedValues.Add(values[start]);
orderedValues.Add(values[end]);
start++;
end--;
}
if (values.Count % 2 != 0)
{
orderedValues.Add(values[values.Count / 2]);
}
var total = 0;
var line = new List<int>();
for (int i = 0; i < orderedValues.Count; i++)
{
var v = orderedValues[i];
total += v;
if (total <= desiredLimit)
{
line.Add(v);
}
else
{
total = v;
result.Add(line);
line = new List<int>() { v };
}
}
result.Add(line);
}
return result;
}
答案 4 :(得分:0)
尝试非常基本的东西
public static List<List<int>> Balance(List<int> input)
{
var result = new List<List<int>>();
if (input.Count > 0)
{
var values = new List<int>(input);
values.Sort();
var max = values.Max();
var maxIndex = values.FindIndex(v => v == max);
for (int i = maxIndex; i < values.Count; i++)
{
result.Add(new List<int> { max });
}
var limit = maxIndex;
for (int i = 0; i < limit / 2; i++)
{
result.Add(new List<int> { values[i], values[(limit - 1) - i] });
}
if (limit % 2 != 0)
{
result.Add(new List<int> { values[limit / 2] });
}
}
return result;
}
此方法可用于需要按两个元素分组的情况。您可以将其更改为组元素,直到达到预定义值(例如10)。可能我会将其他版本发布到。
答案 5 :(得分:0)
如果您有两列,这听起来像是分区问题的应用。问题是NP完全,但有一个动态编程解决方案是伪多项式时间。 http://en.wikipedia.org/wiki/Partition_problem
如果增加列数超过2,则没有伪多项式时间解决方案。 http://en.wikipedia.org/wiki/3-partition_problem
答案 6 :(得分:0)
以下是实现公认答案的通用代码:
首先对项目进行排序(从大到小),这将大大改善
class Item { internal Item(int weight) { Weight = weight; } internal int Weight { get; } }
[Test]
public void Test1() {
var A = new Item(5);
var B = new Item(3);
var C = new Item(7);
var D = new Item(2);
var E = new Item(3);
Item[][] result = AlgoToBuildBalancedPartition.Go(new[] { A, B, C, D, E }, t => t.Weight, 3);
Assert.AreEqual(result.Length, 3);
Assert.Contains(C, result[0]);
Assert.Contains(A, result[1]);
Assert.Contains(D, result[1]);
Assert.Contains(B, result[2]);
Assert.Contains(E, result[2]);
}
//--------------------------------------------------
public static class AlgoToBuildBalancedPartition {
public static T[][] Go<T>(
IEnumerable<T> seq,
Func<T, int> getWeightProc,
int maxNbPartitions) where T : class {
Debug.Assert(!seq.IsNullOrEmpty());
Debug.Assert(getWeightProc != null);
Debug.Assert(maxNbPartitions >= 2);
var partitions = new List<Partition<T>>(maxNbPartitions);
T[] seqDescending = seq.OrderByDescending(getWeightProc).ToArray();
int count = seqDescending.Length;
for (var i = 0; i < count; i++) {
T item = seqDescending[i];
if (partitions.Count < maxNbPartitions) {
partitions.Add(new Partition<T>(item, getWeightProc));
continue;
}
// Get partition with smallest weight
Debug.Assert(partitions.Count == maxNbPartitions);
var partitionWithMinWeight = partitions[0];
for (var j = 1; j < maxNbPartitions; j++) {
var partition = partitions[j];
if (partition.TotalWeight > partitionWithMinWeight.TotalWeight) { continue; }
partitionWithMinWeight = partition;
}
partitionWithMinWeight.AddItem(item);
}
return partitions.Select(p => p.Items.ToArray()).ToArray();
}
private sealed class Partition<T> where T : class {
internal Partition(T firstItem, Func<T, int> getWeightProc) {
Debug.Assert(firstItem != null);
Debug.Assert(getWeightProc != null);
m_GetWeightProc = getWeightProc;
AddItem(firstItem);
}
private readonly Func<T, int> m_GetWeightProc;
internal List<T> Items { get; } = new List<T>();
internal void AddItem(T item) {
Debug.Assert(item != null);
Items.Add(item);
TotalWeight += m_GetWeightProc(item);
}
internal int TotalWeight { get; private set; } = 0;
}
}