ผลต่างระหว่างรุ่นของ "418531 ภาคต้น 2552/โจทยปัญหาอัลกอริทึมแบบแบ่งแยกแล้วเอาชนะ/เฉลยข้อ 4"
Cardcaptor (คุย | มีส่วนร่วม) (→วัตถุ) |
Cardcaptor (คุย | มีส่วนร่วม) |
||
(ไม่แสดง 4 รุ่นระหว่างกลางโดยผู้ใช้คนเดียวกัน) | |||
แถว 35: | แถว 35: | ||
(ข้อสังเกต: lemma 2 และ lemma 3 เป็นข้อความที่มีความสำคัญมากเนื่องจากมันรับประกันว่าจะีมี <math>i \,</math> และ <math>j \,</math> เีพียงคู่เดียวเท่านั้นที่จะสอดคล้องกับเงื่อนไขทั้งหมดใน lemma 1) | (ข้อสังเกต: lemma 2 และ lemma 3 เป็นข้อความที่มีความสำคัญมากเนื่องจากมันรับประกันว่าจะีมี <math>i \,</math> และ <math>j \,</math> เีพียงคู่เดียวเท่านั้นที่จะสอดคล้องกับเงื่อนไขทั้งหมดใน lemma 1) | ||
− | == | + | == อัลกอริทึม == |
− | อาศัย Proposition 4 เราจะแก้ปัญหานี้ด้วยการทำ binary search บนวัตถุคู่ำลำดับ <math>(i,j) \,</math> โดยที่ <math>i+j = k-1 \,</math> โดยเราจะได้ว่าคู่ำลำดับนี้จะมีอยู่อย่างมาก <math>k \,</math> ตัวด้วยกัน ได้แต่ <math>(0,k-1), (1,k-2), (2,k-3), \ldots, (k-2,1), (k-1,0) \</math> | + | อาศัย Proposition 4 เราจะแก้ปัญหานี้ด้วยการทำ binary search บนวัตถุคู่ำลำดับ <math>(i,j) \,</math> โดยที่ <math>i+j = k-1 \,</math> โดยเราจะได้ว่าคู่ำลำดับนี้จะมีอยู่อย่างมาก <math>k \,</math> ตัวด้วยกัน ได้แต่ <math>(0,k-1), (1,k-2), (2,k-3), \ldots, (k-2,1), (k-1,0) \,</math> |
+ | |||
+ | สำหรับวัตถุแต่ละอัน เราจะทำการเปรียบเทียบสองครั้ง ได้แก่ (1) เปรียบเทียบ <math>A[i+1] \,</math> กับ <math>B[j] \,</math> และ (2) เปรียบเทียบ <math>B[j+1] \,</math> กับ <math>A[i] \,</math> โดยการเปรียบเทียบนี้เกิดผลได้ 3 แบบด้วยกัน | ||
+ | * <math>A[i+1] > B[j] \,</math> และ <math>B[j+1] > A[i] \,</math>: ในกรณีเราจะได้ว่าเราหา <math>(i,j) \,</math> ที่ต้องการเจอแล้ว เราสามารถหยุดการทำงานของ binary search ได้ | ||
+ | |||
+ | * <math>A[i+1] > B[j] \,</math> และ <math>B[j+1] < A[i] \,</math>: ในกรณีเราพบว่าสำหรับคู่ลำดับ <math>(i', j') \,</math> อื่นๆ ที่ <math>i' > i \,</math> เราจะได้ว่า <math>A[i'+1] > A[i+1] > B[j] > B[j'] \,</math> และ <math>B[j'+1] \leq B[j] < A[i] < A[i'] \,</math> ด้วยเหตุนี้ <math>(i',j') \,</math> จึีงไม่สามารถนำไปสู่จำนวนที่มีค่าน้อยที่สุดเป็นอันดับที่ <math>k \,</math> ได้ ฉะนั้นในกรณีนี้เราสามารถตัดวัตถุ <math>(i',j') \,</math> โดยที่ <math>i' > i \,</math> ออกจากวัตถุที่เป็นไปได้ทั้งหมด | ||
+ | |||
+ | * <math>A[i+1] < B[j] \,</math> และ <math>B[j+1] > A[i] \,</math>: ในกรณีเราพบว่าสำหรับคู่ลำดับ <math>(i', j') \,</math> อื่นๆ ที่ <math>i' < i \,</math> เราจะได้ว่า <math>A[i'+1] < A[i+1] < B[j] < B[j'] \,</math> และ <math>B[j'+1] > B[j+1] > A[i] > A[i'] \,</math> ด้วยเหตุนี้ <math>(i',j') \,</math> จึีงไม่สามารถนำไปสู่จำนวนที่มีค่าน้อยที่สุดเป็นอันดับที่ <math>k \,</math> ได้ ฉะนั้นในกรณีนี้เราสามารถตัดวัตถุ <math>(i',j') \,</math> โดยที่ <math>i' < i \,</math> ออกจากวัตถุที่เป็นไปได้ทั้งหมด | ||
+ | |||
+ | จากแนวคิดข้างต้น เราสามารถเขียน pseudocode ของอัลกอริืทึมได้ดังต่อไปนี้ | ||
+ | |||
+ | <geshi lang="c"> | ||
+ | Search(A, B, k) | ||
+ | { | ||
+ | i_left = 0 | ||
+ | i_right = k-1 | ||
+ | |||
+ | while i_left <= i_right do | ||
+ | { | ||
+ | i = (i_left + i_right) / 2 | ||
+ | j = k - 1 - i | ||
+ | |||
+ | if A[i+1] > B[j] and B[j+1] > A[i] then | ||
+ | return min(A[i+1], B[j+1]) | ||
+ | else if A[i+1] > B[j] and B[j+1] < A[i] then | ||
+ | i_right = i-1 | ||
+ | else if A[i+1] < B[j] and B[j+1] > A[i] then | ||
+ | i_left = i+1 | ||
+ | } | ||
+ | } | ||
+ | </geshi> | ||
+ | |||
+ | เนื่องจากในการเช็คเงื่อนไขแต่ละครั้งเราสามารถตัดวัตถุที่เป็นไปได้ออกประมาณครึ่งหนึ่ง เราจะได้ว่าจะมีการวนลูปใน pseudocode อย่างมาก <math>O(\log k) = O(\log(m+n)) = O(\log m + \log n) \,</math> ครั้ง ฉะนั้นอัลกอริทึมข้างบนจึงทำงานภายในเวลา <math>O(\log n + \log m)\,</math> ตามต้องการ |
รุ่นแก้ไขปัจจุบันเมื่อ 14:28, 2 กันยายน 2552
ในปัญหาข้อนี้เราจะใช้ binary search เหมือนกับปัญหาข้อที่ผ่านๆ มา แต่วัตถุที่เราทำการค้นหาจะแตกต่างจากข้ออื่นมาก
เพื่อความสะดวก เราจะกำหนดให้อะเรย์ และ มีช่อง และ โดยที่ และ กล่าวคือ และ จะมีค่าน้อยกว่าอะเรย์ช่องอื่นๆ ทั้งหมด แต่เราจะไม่นับว่าช่องที่เพิ่มมาใหม่นี้เป็นส่วนหนึ่งของอะเรย์
เราจะพิสูจน์ข้อความสามข้อความต่อไปนี้
lemma 1: ถ้า และ เป็นจำนวนเต็มที่
- และ
- และ
- และ
- และ
แล้วสมาชิกตัวที่น้อยที่สุดเป็นอันดับที่ ในอะเรย์ และ คือ
พิสูจน์: ให้ เป็นจำนวนที่น้อยกว่าระหว่าง และ แล้วจะได้ว่ามีจำนวน ตัวใน ที่น้อยกว่า และจำนวน ตัวใน ที่น้อยกว่ามัน ฉะนั้นมีจำนวน ตัวใน และ ที่น้อยกว่ามันพอดี ดังนั้น เป็นสมาชิกตัวที่น้อยที่สุดเป็นอันดับที่ พอดี
lemma 2: ถ้า คือจำนวนที่มีค่าน้อยที่สุดเป็นอันดับที่ ใน และ โดยที่ แล้ว หากให้ แล้ว เราจะได้ว่า และ
พิสูจน์: เนื่องจาก เป็นสมาชิกตัวที่น้อยที่สุดเป็นอันดับที่ ดังนั้นจะต้องมีสมาชิกใน และ ที่น้อยกว่ามัน ตัวพอดี และเนื่องจากมีสมาชิกที่น้อยกว่า อยู่ ตัวในอะเรย์ จะต้องมีสมาชิกที่้น้อยกว่า อยู่ ตัวใน ซึ่งนี่หมายความว่า
อนึ่ง เราจะได้ว่า ด้วย ฉะนั้น lemma เป็นจริง
lemma 3: ถ้า คือจำนวนที่มีค่าน้อยที่สุดเป็นอันดับที่ ใน และ โดยที่ แล้ว หากให้ แล้ว เราจะได้ว่า และ
พิสูจน์: ใช้วิธีพิสูจน์เดียวกันกับ lemma 2
สังเกตว่า lemma 2 และ lemma 3 เป็น converse ของ lemma 1 ฉะนั้นเราสามารถสรุปได้ว่า
Proposition 4: เราสามารถหาสมาชิกตัวที่มีค่าน้อยที่สุดเป็นอันดับ ในอะเรย์ และ ได้โดยการหาจำนวนเต็ม และ ที่ทำให้ (1) และ (2) และ (3) แล้วจึีงหาคำตอบด้วยการหาค่าที่น้อยกว่าระหว่าง และ
(ข้อสังเกต: lemma 2 และ lemma 3 เป็นข้อความที่มีความสำคัญมากเนื่องจากมันรับประกันว่าจะีมี และ เีพียงคู่เดียวเท่านั้นที่จะสอดคล้องกับเงื่อนไขทั้งหมดใน lemma 1)
อัลกอริทึม
อาศัย Proposition 4 เราจะแก้ปัญหานี้ด้วยการทำ binary search บนวัตถุคู่ำลำดับ โดยที่ โดยเราจะได้ว่าคู่ำลำดับนี้จะมีอยู่อย่างมาก ตัวด้วยกัน ได้แต่
สำหรับวัตถุแต่ละอัน เราจะทำการเปรียบเทียบสองครั้ง ได้แก่ (1) เปรียบเทียบ กับ และ (2) เปรียบเทียบ กับ โดยการเปรียบเทียบนี้เกิดผลได้ 3 แบบด้วยกัน
- และ : ในกรณีเราจะได้ว่าเราหา ที่ต้องการเจอแล้ว เราสามารถหยุดการทำงานของ binary search ได้
- และ : ในกรณีเราพบว่าสำหรับคู่ลำดับ อื่นๆ ที่ เราจะได้ว่า และ ด้วยเหตุนี้ จึีงไม่สามารถนำไปสู่จำนวนที่มีค่าน้อยที่สุดเป็นอันดับที่ ได้ ฉะนั้นในกรณีนี้เราสามารถตัดวัตถุ โดยที่ ออกจากวัตถุที่เป็นไปได้ทั้งหมด
- และ : ในกรณีเราพบว่าสำหรับคู่ลำดับ อื่นๆ ที่ เราจะได้ว่า และ ด้วยเหตุนี้ จึีงไม่สามารถนำไปสู่จำนวนที่มีค่าน้อยที่สุดเป็นอันดับที่ ได้ ฉะนั้นในกรณีนี้เราสามารถตัดวัตถุ โดยที่ ออกจากวัตถุที่เป็นไปได้ทั้งหมด
จากแนวคิดข้างต้น เราสามารถเขียน pseudocode ของอัลกอริืทึมได้ดังต่อไปนี้
<geshi lang="c"> Search(A, B, k) {
i_left = 0 i_right = k-1
while i_left <= i_right do { i = (i_left + i_right) / 2 j = k - 1 - i
if A[i+1] > B[j] and B[j+1] > A[i] then return min(A[i+1], B[j+1]) else if A[i+1] > B[j] and B[j+1] < A[i] then i_right = i-1 else if A[i+1] < B[j] and B[j+1] > A[i] then i_left = i+1 }
} </geshi>
เนื่องจากในการเช็คเงื่อนไขแต่ละครั้งเราสามารถตัดวัตถุที่เป็นไปได้ออกประมาณครึ่งหนึ่ง เราจะได้ว่าจะมีการวนลูปใน pseudocode อย่างมาก ครั้ง ฉะนั้นอัลกอริทึมข้างบนจึงทำงานภายในเวลา ตามต้องการ