我有一个项目列表,我想将其划分为子集。为了便于讨论,我们可以说它们是文件。我希望每个子集最多包含5个文件,如果可能的话,子集中文件的总大小应小于1 MB。如果单个文件超过1MB,则它本身应该是一个子集。
我用稍微更通用的形式编写了这个,使用通用的“项目指标”而不是文件大小。但我怀疑有更简单和/或更好的方法来做到这一点。有什么建议?
这就是我所拥有的:
public static IEnumerable<IEnumerable<T>> InSetsOf<T>(this IEnumerable<T> source, int maxItemsPerSet, int maxMetricPerSet, Func<T, int> getMetric)
{
int currentMetricSum = 0;
List<T> currentSet = new List<T>();
foreach (T listItem in source)
{
int itemMetric = getMetric(listItem);
if (currentSet.Count > 0 &&
(currentSet.Count >= maxItemsPerSet || (currentMetricSum + itemMetric) > maxMetricPerSet))
{
yield return currentSet;
//Start a new subset
currentSet = new List<T>();
currentMetricSum = 0;
}
currentSet.Add(listItem);
currentMetricSum += itemMetric;
}
//Return the last set
yield return currentSet;
}
答案 0 :(得分:2)
Bin包装是NP难问题。获得最佳解决方案的唯一方法是测试所有组合。如果存在固定数量的不同大小,则可以使用动态编程系统地完成(对于这种情况,存在answer on SO示例代码),但这种算法的运行时间很糟糕。
这意味着您应该寻找一种启发式方法,让您在合理的时间内接近最佳解决方案。你的算法(first-fit)是一个很好的起点。只需稍加努力,就可以通过减小尺寸来预先计算物品来略微改善。然而,还有一些其他或多或少复杂的启发式方法可以提高速度和结果。
Google search将其作为结果之一返回:Basic analysis of bin-packing heuristics(有paper分析结果)。显然,具有bin查找表的最佳拟合算法在合理的运行时间内提供了良好的结果。
答案 1 :(得分:0)
缺少1MB测试,但是否则您的代码看起来不错。我认为没有一种明显更好的方法。