Алгоритм у відсотках, не знаючи загальної кількості


17

Припустимо, є nлінії для гарячої лінії.

Щоразу, коли клієнт телефонує на «гарячу лінію», дзвінок пересилається на одну з nліній. І я хочу призначити відсоток дзвінків кожній із п ліній. Припустимо, є дві лінії, а одній лінії присвоєно 60%, а іншій - 40%, загальна кількість дзвінків - 10, тому перша лінія отримає 6 дзвінків, а друга отримає 4 виклики.

Я знаю відсоток дзвінків на кожну лінію заздалегідь, але проблема полягає в тому, що я не знаю кількість дзвінків, які надійшли б за день.

Як я можу розподілити кількість дзвінків, не знаючи загальної кількості викликів?


2
Після того, як на рядок 1 надійде 6 дзвінків, надайте лінію 2 4 виклики. Тобто, небайдуже до фактичного загального підрахунку, дбайте про розподіл за "періодом" (10 у даному випадку), який ви знаєте. Очевидно, ви можете робити такі речі, як альтернативні лінії, за винятком останнього значення, тому немає необхідності також чіткого очікування. Якщо є якась черга, зробіть відсоток на основі поточних рядків у черзі.
Завод-Муза

що таке "зірочка" та "DID"?
гнат

@ Clockwork-Muse: Я б запропонував округлення цілих чисел тут, а не підтримку розподілу 6-4. Інакше ваш розподіл буде вимкнено, якщо ви не знаєте, що у вас є точний кратний 10 дзвінків. Наприклад, якщо входить 6 загальних дзвінків, ваш запропонований підхід призначить їх всім рядку А; тоді як правильнішим підходом було б 4 до A і 2 до B (призначається в порядку ABAABA, якщо ви обираєте цілочисельні підсумки для кожного рядка)
Flater

Відповіді:


26

Зробіть кілька бухгалтерій про вже прийняті дзвінки та обчисліть їх розподіл по 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

...

EDIT: Цей підхід можна вдосконалити, не використовуючи абсолютну різницю, а вибираючи лінію, яка мінімізує суму квадратів усіх відхилень. Це також дасть кращий результат, якщо ви точно досягнете цільових значень.


2
Ви можете змінити це "до тих пір, поки" на більш чітке "використовувати інше посилання" FWIW.
DougM

@DougM: див. Мою редакцію.
Док Браун

5
  • Припустимо, кількість працівників менше 100
  • Створіть масив працівників місткістю 100
  • Помістіть у цей масив робітника в кілька разів, рівний відсотковій кількості дзвінків, які він повинен отримувати, наприклад, якщо работник1 повинен отримати 30% усіх дзвінків, а потім помістіть його в позиції від 0 до 29 масиву.
  • Зрештою, слід використовувати кожну позицію масиву, а працівники повинні з’являтися в масиві стільки разів, скільки відсотків викликів, які вони повинні отримувати.
  • У циклі генеруйте випадкове число від 0 до 99 та призначте вхідний дзвінок працівнику в цьому положенні масиву. Якщо працівник зайнятий, повторіть.
  • Таким чином, з великої ймовірності, дзвінки будуть розподілятися за бажанням
  • У моєму прикладі, у робочого1 є шанс 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, який слідує за рядком 2, оскільки -10 % менше 10%. Отже, на лінію 1 отримає дзвінок.

    Я настійно рекомендую використовувати сортування вставки, оскільки вона найкраще працює, коли масив вже в основному відсортований.

Крім того, як незначна оптимізація, якщо ви відстежуєте загальну кількість викликів до цього часу, а не обчислювати фактичний відсоток кожної лінії, ви можете просто обчислити загальну кількість дзвінків за цю лінію за вирахуванням очікуваного відсотка для цього рядок разів загальна кількість викликів (delta = t_i - p_i * T). У цьому випадку дельта - це просто негативна кількість викликів для досягнення очікуваного відсотка.

Я сподіваюся, що це прояснить будь-які інші сумніви.


дякую @Neil, ти мені справді допоміг, але коли обидва потрапили до позначки, то за яку лінію я повинен зателефонувати, чи є якісь критерії для цього.
akku

@akku З моїм алгоритмом ви просто приймаєте перше завжди після сортування, тобто алгоритм не хвилює. Якщо у вас є інші критерії, які потрібно застосувати, ви повинні змусити їх зважити відповідно під час сортування. Іншими словами, якщо номер рядка був важливим, вам слід взяти дельту, помножити на загальну кількість рядків, а потім додати номер поточного рядка. Це сприяє більш високим номерам рядків, припускаючи, що всі інші рівні.
Ніл

@Neil: ваша відповідь чудова, але щоразу, коли я бачу когось, який пропонує повністю сортувати масив, щоб знайти мінімальне значення, я думаю: "Великий Скотт, чи справді це потрібно?"
Док Браун

@DocBrown O(n)- це те, що ви можете очікувати, відсортувавши вже відсортований список із сортуванням вставки, і O(n)це те, що ви повинні використати, щоб знайти найменше значення. Я просто припускаю, що це було відсортовано.
Ніл

@Neil: тільки тому, що два алгоритми є обома O (n), вони не однаково прості (або однаково швидкі).
Док Браун

2

Припущення, як заявлено в ОП

  1. Відомо число рядків, n, і;
  2. % Кожного рядка відомі

Дизайн алгоритму

  1. Визначте кожен рядок на його%

  2. Сортуйте кожен рядок за його положенням від 0, визначеного як (поточний% працівників - призначений% працівників) або за випадковим призначенням, якщо всі рядки = 0

  3. Переадресація кожного дзвінка на найбільшу лінію від 0

Приклад: 3 рядки з% 20, 30 і 50 відповідно. У той час, коли х людина дзвонить 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.