“ ปัญหาการหยิบพิซซ่า” แก้ไขได้อย่างไรโดยใช้เทคนิคการเขียนโปรแกรมแบบไดนามิก?


9

ปัญหาการเลือกพิซซ่าของ Winkler:

  • พายพิซซ่าวงกลมของnชิ้นที่ชิ้นiมีพื้นที่S_iเช่นพื้นที่ที่แตกต่างกันสำหรับแต่ละชิ้นพาย
  • ผู้เสพอลิซและบ๊อบผลัดกันหยิบชิ้น แต่มันหยาบคายที่จะสร้างช่องว่างหลายแห่งในวงกลม (พิจารณาว่าไม่ได้รับอนุญาต)
    • ดังนั้นผู้กินแต่ละคนจะถูก จำกัด ให้รับหนึ่งในสองชิ้นติดกับพื้นที่เปิด อลิซไปก่อนแล้วผู้เสพทั้งคู่หาทางพายให้ได้มากที่สุด

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

ความเข้าใจของฉัน:

ในปัญหา DP ทั่วไปเราดำเนินการต่อไปด้วยการค้นหาปัญหาย่อยซึ่งสามารถมองเห็นได้โดยใช้แผนผังการเรียกซ้ำหรือใช้ DAG ให้แน่นขึ้น ที่นี่ฉันไม่พบโอกาสในการค้นหาปัญหาย่อยที่นี่

ที่นี่สำหรับชุด S_i s หนึ่งชุดเราต้องเพิ่มพื้นที่ส่วนที่กินโดย Alice ให้มากที่สุด สิ่งนี้จะขึ้นอยู่กับการเลือกวิธีเรียงสับเปลี่ยนชิ้นพิซซ่า (n-1) เรียงสับเปลี่ยน การเลือกชิ้นส่วนพื้นที่สูงสุดจากสองตัวเลือกที่มีอยู่ในทุก ๆ n \ 2 ทำให้อลิซได้รับแล้วจะให้พื้นที่ทั้งหมดของชิ้นเพื่อเปลี่ยนรูป เราจำเป็นต้องค้นหาพื้นที่ของชิ้นสำหรับการเรียงสับเปลี่ยนทั้งหมด แล้วค่าสูงสุดจากสิ่งเหล่านี้

ใครสามารถช่วยฉันในการก้าวไปข้างหน้า?

คำตอบ:


5

เริ่มต้นด้วยการพิจารณาชิ้นที่เพิ่งวางบนแถวและคุณสามารถเลือกจากหนึ่งในสองปลาย ในกรณีนี้สมมติว่าเป็นตาคุณที่จะเลือกอย่างชัดเจนนั่นpizzaAmount(slices)คือ

  1. หากไม่มีพิซซ่าเหลือผลลัพธ์คือ 0
  2. หากมีเพียงหนึ่งชิ้นผลคือชิ้นนั้น
  3. หากมีอย่างน้อยสองชิ้นผลลัพธ์ก็คือ:

(ใช้ไวยากรณ์ Python)

max(slices[0] + sum(slices[1:]) - pizzaAmount(slices[1:]),
    slices[-1] + sum(slices[:-1]) - pizzaAmount(slices[:-1]))

กล่าวอีกนัยหนึ่งคุณควรพิจารณาทั้งทางเลือกและหลังจากการแบ่งส่วนของคุณคุณจะได้รับพิซซ่าที่เหลือทั้งหมดยกเว้นผลของการโทรซ้ำ (เพราะเพื่อนของคุณจะใช้กลยุทธ์เดียวกัน)

คุณสามารถใช้สิ่งนี้กับ DP (หรือการบันทึก) เนื่องจากอาร์เรย์ได้รับการแก้ไขแน่นอนและคุณสามารถพิจารณาว่าเป็นพารามิเตอร์ของดัชนีชิ้นแรกและชิ้นสุดท้าย

ในการแก้ปัญหาแบบเต็มตัวคุณต้องลองชิ้นทั้งหมดเป็นชิ้นเริ่มต้นและเลือกชิ้นที่เพิ่มผลลัพธ์ให้ได้มากที่สุด


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

เพียงแค่อยากรู้อยากเห็นลำดับความซับซ้อนของอัลกอริทึมนี้คืออะไร? 0 (n * 2 ^ n)?

@Aron: นี่คือสิ่งที่มันจะเป็นโดยไม่ต้องใช้วิธีการเขียนโปรแกรมแบบไดนามิกหรือบันทึก อย่างไรก็ตามคุณสามารถใช้ประโยชน์จากข้อเท็จจริงที่ว่าผลลัพธ์pizzaAmountนั้นขึ้นอยู่กับดัชนีเริ่มต้นและหยุดของชิ้นส่วนที่เหลือเท่านั้นและไม่ได้อยู่ในลำดับที่ชิ้นส่วนพิซซ่าคุณและเพื่อนของคุณทานเพื่อให้คุณสามารถเก็บผลลัพธ์ไว้ใน เมทริกซ์เพื่อหลีกเลี่ยงการคำนวณใหม่ คำสั่งของอัลกอริทึมคือ O (n ** 2)
6502

หากใครยังคงดิ้นรนที่จะเข้าใจลิงค์นี้มีคำอธิบายที่ดีมาก
Amit Shekhar

3

สำหรับส่วนหนึ่งของพิซซ่ากำหนดF(i,j)เป็นจำนวนสูงสุดที่บุคคลที่เลือกชิ้นแรกสามารถกิน ชิ้นส่วนของพิซซ่า(i,j)คือ:

if i <= j than slices i, i+1, ..., j-1, j
if i > j than slices i, i+1, ..., n-1, n, 1, 2, ..., j-1, j
and we don't define it for whole pizza, abs(i-j) < n-1

กําหนดR(i,j)(เท่าใดซ้ายสำหรับคนที่สอง) sum(S_x, x in slices(i,j)) - F(i,j)ในฐานะ

ด้วย:

F(i,i) = S_i,
F(i,j) = max( S_i + R(i+1,j), S_j + R(i,j-1) ),

มากที่สุดที่อลิซสามารถกินได้คำนวณโดย:

max( S_i + F(i+1, (i-1) if i > 1 else n) ).
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.