อัลกอริทึมสำหรับเปอร์เซ็นต์โดยไม่ทราบจำนวนรวม


17

สมมติว่ามีnเส้นสำหรับสายด่วน

เมื่อใดก็ตามที่ลูกค้าโทรสายด่วนสายจะถูกส่งต่อไปยังหนึ่งในnสาย และฉันต้องการกำหนดเปอร์เซ็นต์ของการโทรไปยังแต่ละบรรทัด n สมมติว่ามีสองบรรทัดและหนึ่งบรรทัดถูกกำหนด 60% และอื่น ๆ คือ 40% จำนวนการโทรทั้งหมดคือ 10 ดังนั้นสายแรกจะได้รับ 6 การโทรและครั้งที่สองจะได้รับการโทร 4 ครั้ง

ฉันรู้เปอร์เซ็นต์ของการโทรไปยังแต่ละสายล่วงหน้า แต่ปัญหาคือฉันไม่รู้จำนวนการโทรที่จะได้รับในหนึ่งวัน

ฉันจะกระจายจำนวนการโทรโดยไม่รู้การโทรทั้งหมดได้อย่างไร?


2
หลังจากสาย 1 ได้รับ 6 สายให้โทรสาย 2 4 นั่นคือไม่ต้องสนใจจำนวนจริงทั้งหมดสนใจเกี่ยวกับการแจกแจงใน "ระยะเวลา" (10 ในกรณีนี้) ที่คุณรู้ เห็นได้ชัดว่าคุณสามารถทำสิ่งต่าง ๆ เช่นบรรทัดสำรองยกเว้นค่าสุดท้ายดังนั้นจึงไม่จำเป็นต้องรออย่างเข้มงวดเช่นกัน หากมีคิวเรียงลำดับให้ทำเปอร์เซ็นต์ตามแถวปัจจุบันในคิว
Clockwork-Muse

"เครื่องหมายดอกจัน" และ "DID" คืออะไร
ริ้น

@ Clockwork-Muse: ฉันอยากจะแนะนำให้ปัดเศษเป็นจำนวนเต็มตรงนี้แทนที่จะเก็บไว้ 6-4 ตัว มิฉะนั้นการกระจายของคุณจะถูกปิดเว้นแต่คุณจะรู้ว่าคุณมีการโทรหลายสายที่แน่นอน 10 ครั้ง เช่นถ้ามีการโทรเข้ามาทั้งหมด 6 ครั้งวิธีที่คุณแนะนำจะกำหนดให้ทุกคนอยู่ในสาย A ในขณะที่วิธีการที่ถูกต้องมากขึ้นจะเป็น 4 ถึง A และ 2 ถึง B (มอบหมายตามคำสั่ง ABAABA หากคุณปัดจำนวนผลรวมที่ได้รับมอบหมายจำนวนเต็มสำหรับแต่ละบรรทัด)
Flater

คำตอบ:


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
คุณอาจต้องการเปลี่ยนที่ "ตราบใดที่" เป็น "ชัดเจนยิ่งขึ้น" ใช้การอ้างอิง tiebreaker อื่น "FWIW
DougM

@DougM: ดูการแก้ไขของฉัน
Doc Brown

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 จะได้รับการโทร

    ฉันขอแนะนำให้ใช้การเรียงลำดับการแทรกเนื่องจากมันจะทำงานได้ดีที่สุดเมื่อเรียงลำดับเป็นส่วนใหญ่อยู่แล้ว

เช่นเดียวกับการปรับให้เหมาะสมเล็กน้อยหากคุณติดตามจำนวนการโทรทั้งหมดจนถึงตอนนี้แทนที่จะต้องคำนวณเปอร์เซ็นต์ที่แท้จริงของแต่ละสายคุณสามารถคำนวณจำนวนการโทรทั้งหมดสำหรับสายนั้นลบด้วยเปอร์เซ็นต์ที่คาดหวังสำหรับสายนั้น line คูณจำนวนการโทรทั้งหมด (delta = t_i - p_i * T) ในกรณีนี้ delta คือจำนวนการโทรติดลบเพื่อให้ได้เปอร์เซ็นต์ที่คาดหวัง

ฉันหวังว่าจะชี้แจงข้อสงสัยอื่น ๆ


ขอบคุณ @Neil คุณช่วยฉันจริง ๆ แต่เมื่อทั้งคู่ตีเครื่องหมายดังนั้นฉันควรจะโทรหาสายไหนบรรทัดนั้นมีเกณฑ์อะไรบ้าง
akku

@akku ด้วยอัลกอริทึมของฉันคุณเพียงแค่แรกเสมอหลังจากเรียงลำดับหมายความว่าอัลกอริทึมไม่สนใจ หากคุณมีเกณฑ์อื่นที่จะนำไปใช้คุณต้องทำให้มีน้ำหนักตามนั้นเมื่อคุณจัดเรียง กล่าวอีกนัยหนึ่งถ้าหมายเลขบรรทัดมีความสำคัญคุณควรใช้เดลต้าคูณด้วยจำนวนบรรทัดทั้งหมดแล้วเพิ่มหมายเลขบรรทัดปัจจุบัน ที่โปรดปรานหมายเลขบรรทัดที่สูงกว่าสมมติว่าทุกคนเท่าเทียมกัน
Neil

@ Neil: คำตอบของคุณก็ดี แต่เมื่อใดก็ตามที่ฉันเห็นมีคนแนะนำให้เรียงลำดับอาร์เรย์อย่างสมบูรณ์เพื่อหาค่าต่ำสุดฉันคิดว่า "Great Scott นี่เป็นสิ่งที่จำเป็นจริงๆเหรอ?"
Doc Brown

@DocBrown O(n)คือสิ่งที่คุณสามารถคาดหวังการเรียงลำดับรายการที่เรียงแล้วด้วยการเรียงลำดับการแทรกและO(n)เป็นสิ่งที่คุณต้องใช้เพื่อค้นหาค่าที่น้อยที่สุด ฉันแค่คิดว่ามันมีการจัดเรียง
Neil

@ Neil: เพียงเพราะอัลกอริธึมทั้งสองเป็นทั้ง O (n) พวกมันจึงไม่ง่ายอย่างเท่าเทียมกัน (หรือเร็วพอ ๆ กัน)
Doc Brown

2

ข้อสันนิษฐานตาม OP ระบุไว้

  1. จำนวนบรรทัด, n, เป็นที่รู้จักและ;
  2. รู้จัก% ของแต่ละบรรทัด

การออกแบบอัลกอริทึม

  1. กำหนดแต่ละบรรทัดด้วย%

  2. จัดเรียงแต่ละบรรทัดตามตำแหน่งของมันห่างจาก 0 กำหนดเป็น (ปัจจุบัน% ของผู้ปฏิบัติงาน - กำหนด% ของผู้ปฏิบัติงาน) หรือโดยการมอบหมายแบบสุ่มถ้าทุกสาย = 0

  3. โอนสายแต่ละสายที่ใหญ่ที่สุดห่างจาก 0

ตัวอย่าง: 3 บรรทัดที่มี% 20, 30 และ 50 ตามลำดับ ที่จุด x ในเวลา 1 คนที่โทรและเนื่องจากทุกสายอยู่ห่างจาก 0 มันจะได้รับการสุ่ม - พูดกับสาย 2 ซึ่งควรเก็บ 30% ของการโทรทั้งหมด เนื่องจากบรรทัดที่ 2 ควรพักสาย 30% ของการโทรทั้งหมดและตอนนี้รับสาย 100% ของการโทรทั้งหมดตำแหน่งของมันจะเพิ่มขึ้น 0 ผูโทรคนถัดไปจะถูกกําหนดใหกับสาย 1 หรือ 3 และอื่น ๆ จนกระทั่งสมดุล (0) และวนรอบซ้ําตัวเอง


0

นี่เป็นวิธีการแก้ปัญหาที่ไร้เดียงสาและไม่คิดอะไร แต่จะอนุญาตการกระจายแบบเปอร์เซ็นต์ โซลูชันนี้สามารถปรับปรุงได้หลายวิธี แต่นี่คือส่วนสำคัญของมัน ฉันไม่แน่ใจว่านี่คือสิ่งที่คุณกำลังมองหา แต่มันจะให้การกระจายที่แท้จริง

รหัส psuedo ...

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.