【问题标题】:Distributing Items Evenly Across a Number of Days在几天内平均分配项目
【发布时间】:2014-02-20 22:00:12
【问题描述】:

我需要在固定天数内分发剩余的物品。例如假设我有 197 件物品和 75 天的时间来分发它们。如果我在 75 天内显示 2 个项目,那么我有 47 个项目未显示。如何在 75 天内平均分配剩余的 47 个项目,以便我得到一个像 2,3,3,2,3,3,2,2,3.... 的序列,即 3 均匀分布在整个显示器。这就是我目前所拥有的

const double num = (double)197/75;
double temp = num;
var list = new List<int>();
for (var t = 1; t <= days; t++)
{
    var intPart = int.Parse(Math.Truncate(temp).ToString());

    list.Add(intPart);

    var remainder = num - intPart;

    temp = num + remainder;
}

但我最终只显示了 187 个项目。我错过了 10 个。

【问题讨论】:

  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • 转换成秒怎么样?
  • 感谢您的回复。当我说均匀时,我的意思是我只想在任何一个“桶”中最多放 3 件物品。所以基本上我希望剩余的 47 个项目尽可能均匀地分布在 75 个“桶”中,每个“桶”已经有 2 个项目。我认为通过跟踪剩余的项目可以实现我的目标,但我在想现在我可能需要在将整数插入列表时进行一些重新计算。还有什么想法吗?

标签: c# algorithm distribution


【解决方案1】:

正如 AlexD 所指出的,在某些情况下,原始答案的结果并不理想:

int numItems = 197;
int numDays = 75;
var list = new List<int>();
for (int t = 0; t < numDays; t++)
{
    int numItemsInDay = ((t+1)*numItems+numDays/2)/numDays - (t*numItems+numDays/2)/numDays;
    list.Add(numItemsInDay);
}

想法是每个项目都进入由itemIndex*numDays/numItems的舍入值定义的日期,您可以直接计算一天中的项目数量,而无需跟踪之前的项目。


另一种方法。

要尽可能均匀地将numItems 项目分布在numDays 天之间,您需要将天分组为带有floor(numItems/numDays) 项目的天跨度和带有ceil(numItems/numDays) 项目的天跨度,分布跨度 尽可能均匀。所以问题可以通过递归减少天数到跨度数来解决。

static List<int> Spread(int numDays, int numItems)
{
    List<int> result = new List<int>();
    if (numDays <= 1)
    {
        if (numDays == 1)
            result.Add(numItems);
        return result;
    }
    int numItemsInDayLower = numItems/numDays;
    int numItemsInDayHigher = numItemsInDayLower+1;
    int numDaysHigher = numItems - numItemsInDayLower * numDays;
    int numDaysLower = numDays-numDaysHigher;
    int numSpansLower = numDaysLower > numDaysHigher ? numDaysHigher + 1 : numDaysLower;
    int numSpansHigher = numDaysHigher > numDaysLower ? numDaysLower + 1 : numDaysHigher;
    bool isStartingFromSpanLower = numDaysLower > numDaysHigher;
    List<int> spanLehgthsLower = Spread(numSpansLower, numDaysLower);
    List<int> spanLehgthsHigher = Spread(numSpansHigher, numDaysHigher);
    for (int iSpan = 0; iSpan < spanLehgthsLower.Count + spanLehgthsHigher.Count; iSpan++)
    {
        if ((iSpan % 2 == 0) == isStartingFromSpanLower)
        {
            for (int i = 0; i < spanLehgthsLower[iSpan/2]; i++)
                result.Add(numItemsInDayLower);
        }
        else
        {
            for (int i = 0; i < spanLehgthsHigher[iSpan/2]; i++)
                result.Add(numItemsInDayHigher);
        }
    }
    return result;
}

【讨论】:

  • @AlexD 从数学上讲是的,但是由于整数除法时会发生截断,所以不是。 +1 一个非常好的解决方案,只是一个小建议,考虑使用数组并设置项目而不是添加到列表中;你提前知道会有多少项目。
  • @Lukazoid 是的,当然。谢谢!
  • @Lukazoid 绝对是个好主意,但例如对于days=5 items=3,我们得到01011,而在理想情况下应该是10101
  • 好!我害怕变得无聊,但现在对于6 项目,8 天我们得到11011101 而不是11011011。 (好吧,我们没有“均匀”的正式定义,但直觉上我希望11011011。)
  • 是的,看起来很优雅,+1。一个小评论:难道numDaysLower == numDaysHigher ? numDaysHigher : numDaysLower 总是评估为numDaysLower :)?
猜你喜欢
  • 2018-06-16
  • 1970-01-01
  • 2014-03-09
  • 1970-01-01
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多