不知道总数的百分比算法


17

假设有n热线电话。

每当客户致电热线时,该呼叫就会被转接到其中一条n线路。我想将呼叫百分比分配给n行中的每行。假设有两条线路,一条线路分配了60%,另一条线路分配了40%,呼叫总数为10,因此第一行将收到6个呼叫,第二行将收到4个呼叫。

我知道提前拨打每条线路的百分比,但是问题是我不知道一天会收到多少次电话。

如何在不知道总呼叫数的情况下分配呼叫数?


2
1号线接到6个电话后,给2号线打电话4个。也就是说,不必在乎实际的总数,而在乎您所知道的“期间”(在本例中为10)的分布。显然,除了最后一个值之外,您还可以执行其他行之类的操作,因此也无需严格等待。如果存在某种队列,请根据队列中的当前行执行百分比。
Clockwork-Muse

什么是“星号”和“ DID”?
gna 2014年

@ Clockwork-Muse:我建议在这里四舍五入整数而不是保持6-4分布。否则,除非您知道您有10个通话的确切倍数,否则您的分配将不可用。例如,如果总共有6个呼叫进入,则您建议的方法会将其全部分配给A行;而更正确的方法是将4分配给A,将2分配给B(如果将四舍五入为每一行的整数分配总数,
则按ABAABA

Answers:


26

对已经接听的电话进行簿记,并计算它们在n行上的分布。这将为您提供n个百分比值(您已经实现的分布),可以将其与您想要达到的n个百分比进行比较。每当有新电话打进来时,请将该电话分配给与目标值有最大偏差的那条线(请注意,只要您未完全达到给定的分布,就总会有一条线的电话数过少,与目标分布相比)。

例如:将第一个呼叫分配给第1行后:

 total calls line1      total calls line2    perc.line 1    perc. line 2
 1                      0                    100%             0% 
                                             *above 60%      *below 40% <- next call to 2
 1                      1                    50%             50% 
                                             * below 60%:    *above40% next to line1
 2                      1                    66%             33%
                                             *above 60%      *below 40% <- next to line 2
 2                      2                    50%             50% 
                                             * below 60%:    *above40% next to line1
 3                      2                    60%             40% 
                                             * both hit the mark: next call arbitrary
 4                      2                    66%             33%
                                             *above 60%      *below 40% <- next to line 2
 4                      3                    57.1%             42.85%
                                             *below 60%      *above 40% <- next to line 1

...

编辑:不使用绝对差,而是选择使所有偏差的平方和最小的线可以进一步改进此方法。如果您精确地达到目标值,那也可以给您带来更好的结果。


2
您可能希望将“只要”更改为更明确的“使用其他决胜局”引用FWIW。
DougM 2014年

@DougM:看我的编辑。
布朗

5
  • 假设工人人数少于100
  • 创建一个可容纳100名工人的阵列
  • 将一个工作程序放入该数组的次数等于他应获得的呼叫百分比,例如,如果worker1应该获得所有呼叫的30%,则将其置于该数组的0到29位。
  • 最后,应使用数组的每个位置,并且工作程序应在数组中出现的次数与其应获得的调用百分比相同。
  • 在一个循环中,生成一个介于0到99之间的随机数,然后将传入的调用分配给数组中该位置的worker。如果工人忙,请重复。
  • 这样,在绝对的可能性下,呼叫将按需分配
  • 在我的示例中,worker1在任何给定的迭代中都有30/100的机会被选择。

4

我同意@DocBrown的解决方案。将其放入算法形式:

for each incoming call:
    sort lines ascending by delta* (see footnote below)

    // first element in array gets the call 
    increase number of calls for first element by 1
  • 增量由实际百分比减去行的预期百分比确定。这样,负增量最大的那些是最需要呼叫以符合期望百分比的那些。

    例如,在第1行和第2行的预期百分比分别为60%和40%,而其实际百分比为50%和50%的情况下,您会看到订购行1跟第二行,因为-10 %小于10%。因此,第1行将接听电话。

    我强烈建议使用插入排序,因为它在数组已被多数排序时性能最佳。

另外,作为次要优化,如果您跟踪到目前为止的总呼叫数,而不必计算每条线路的实际百分比,则只需计算该行的总呼叫数减去该行的预期百分比即可线路乘以呼叫总数(delta = t_i-p_i * T)。在这种情况下,增量只是达到预期百分比的呼叫次数的负数。

我希望这可以澄清任何其他疑问。


谢谢@尼尔,你真的帮助了我,但是当两者都达到目标时,那我应该打哪条线,这有什么条件吗?
akku 2014年

@akku使用我的算法,您只需要在排序后始终执行第一个即可,这意味着该算法无关紧要。如果要应用其他条件,则在对它进行排序时必须使其具有相应的权重。换句话说,如果行号很重要,那么您应该使用增量,乘以总行数,然后加上当前行号。假设其他所有条件都相同,则倾向于使用较高的行号。
尼尔

@Neil:您的回答很好,但是每当我看到有人建议对数组进行完全排序只是为了找到最小值时,我认为“伟大的Scott,这真的有必要吗?”
布朗

@DocBrown O(n)是您可以期望使用插入排序对已经排序的列表进行排序的方法,并且它O(n)是查找最小值所需的方法。我只是假设已排序。
尼尔

@Neil:仅仅因为两个算法都是O(n),所以它们不是那么简单(或者同样快)。
布朗

2

如OP所述的假设

  1. 行数n是已知的;
  2. 每行的百分比是已知的

算法设计

  1. 用%定义每行

  2. 按每行距0的位置(定义为当前工人百分比-分配的工人百分比)的位置进行排序;如果所有行= 0,则按随机分配进行排序

  3. 将每个呼叫转移到距离0不远的最大线路

示例:3行,其百分比分别为20、30和50。在时间点x,有1个人呼叫,并且由于每条线路都与0相距0,因此它被随机分配-例如说到第2行,该线路应容纳所有呼叫的30%。由于第2行应保留所有呼叫的30%,现在应保留所有呼叫的100%,因此其位置从0开始增加。现在将下一个呼叫者分配给线路1或线路3等,直到达到平衡(0),然后循环重复进行。


0

这是一个幼稚的解决方案,不做任何假设,但允许基于百分比的分配。该解决方案可以通过许多方式加以改进,但这是其要旨。我不确定这是否是您要寻找的东西,但是它将为您带来真正的分布。

伪代码...

int running_total_of_calls = 0

//This is hard coded for clarity. You'd most likely want to dynamically populate this array depending and probably distribute the work by alternating workers. Notice how "worker1" appears 6 out of 10 times in the array.
string[] worker = new string[10]
workers[0] = "worker1"
workers[1] = "worker1"
workers[2] = "worker1"
workers[3] = "worker1"
workers[4] = "worker1"
workers[5] = "worker1"
workers[6] = "worker2"
workers[7] = "worker2"
workers[8] = "worker2"
workers[9] = "worker2"

while(1) //run forever
    //This is where the distribution occurs. 
    //first iteration: 0 modulus 10 = 0. 
    //second: 1 modulus 10 = 1
    //third: 2 modulus 10 = 2
    //...
    //10th: 10 modulus 10 = 0
    //11th: 11 modulus 10 = 1 
    //12th: 12 modulus 10 = 2
    //...
    int assigned_number = running_total_of_calls % workers.Count //count of workers array
    string assigned_worker = workers[assigned_number]
    do_work(assigned_worker)
    running_total_of_calls = ++running_total_of_calls
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.