Home    Previous page ขั้นตอนวิธีประเภทแบ่งเพื่อเอาชนะ (Divide-and-conquer algorithm) Next page
ขั้นตอนวิธีประเภทแบ่งเพื่อเอาชนะ (Divide-and-conquer algorithm)
เป็นขั้นตอนวิธีการแก้ปัญหาที่ใช้หลักการแบ่งปัญหาออกเป็นส่วนเล็ก ๆ แล้วทำการแก้ปัญหาในส่วนเล็ก ๆ นั้น โดยไม่ขึ้นต่อกัน หลังจากนั้นจึงนำคำตอบที่ได้จากปัญหาย่อยเหล่านั้นมารวมกัน โดยปกติขนาดของข้อมูลที่ถูกแบ่งจะมีขนาดเล็กลง จนถึงระดับหนึ่ง แล้วเราจึงทำการแก้ปัญหาขนาดเล็กนั้น โดยไม่ใช้การเรียกซ้ำ
ตัวอย่างของปัญหาที่สามารถใช้ขั้นตอนวิธีนี้คือ
  • การคูณจำนวนขนาดใหญ่
  • การค้นหาแบบทวิภาค
  • การจัดเรียงข้อมูลแบบ Merge sort และ Quick sort
  • การคูณกันของเมทริกซ์จัตุรัส สองเมทริกซ์

ปัญหาการคูณจำนวนขนาดใหญ่
กำหนดจำนวนสองจำนวนที่มีขนาดใหญ่ โดยปกติแล้วเราสามารถคูณตัวเลขหนึ่งหลักกับตัวเลขหลายหลักได้โดยง่าย และเราทราบว่าการบวกกันของตัวเลขหลายจำนวนใช้เวลาที่น้อยมาก เราควรสร้างขั้นตอนวิธีในการคูณจำนวนเต็มบวกสองจำนวน 981 กับ 1234 อย่างไรถึงจะใช้จำนวนในการคูณของตัวเลขหนึ่งหลักที่น้อยที่สุด
วิธีการคูณแบบปกติ
หลักการคือ เลือกจำนวนที่มีค่ามากกว่าเป็นตัวตั้ง แล้วทำการหยิบเลขทีละตัวจากอีกจำนวนหนึ่งคูณจำนวนตั้งนั้น แล้วจึงทำการบวกกัน ตัวอย่างจงหาผลคูณของ 981 กับ 1234
LONG_MULTI(m, n)
ข้อมูลเข้า m, n เป็นจำนวนที่ต้องการคูณกัน
ข้อมูลออก result เป็นผลคูณที่ได้

1. If m < n 
2.    then swap m and n
3. endif
4. set A[1,..,k] be the number for each digit of n where A[1] is the rightmost digit and A[k] is the leftmost digit
5. result = 0;
6. for i = 1 to k
7.    result = result*10;
8.    result = result + A[i]*m
9. endfor
10. return result

วิธีการคูณโดยการหารสองและคูณสอง
หลักการคือ กำหนดจำนวนหนึ่งเป็นตัวตั้ง เพื่อทำการคูณสองในแต่ละขั้น และตัวคูณซึ่งจะถูกหารสองในแต่ละขั้นจนเป็นศูนย์ แล้วจึงทำการบวกกันเฉพาะแถวของตัวตั้งที่หารแล้วเหลือเศษจากตัวคูณ ตัวอย่างจงหาผลคูณของ 981 กับ 1234
Russe(m, n)
ข้อมูลเข้า m, n เป็นจำนวนที่ต้องการคูณกัน
ข้อมูลออก result เป็นผลคูณที่ได้
1. result = 0
2. repeat
3.    if m is odd 
4.       then result = result + n
5.       m = m ÷ 2
6.       n = n + n
7. until m < 1
8. return result
เมื่อ m ÷ 2 หมายถึง จำนวนเต็มที่ได้หลังจากนำ 2 ไปหาร m

วิธีการคูณโดย Divide-and-Conquer
หลักการคือการลดจำนวนของตัวเลขที่จะคูณโดยคูณเพียงครึ่งหนึ่งของจำนวนตัวเลขเดิม
MULTI_DC(m, n)
ข้อมูลเข้า m, n เป็นจำนวนที่ต้องการคูณกัน
ข้อมูลออก result เป็นผลคูณที่ได้
1. Make sure that m and n contains the number of digits in the power of two.
2. result = 0
3. if m or n has one digit 
4.     then result = m * n
5.     return result
6. endif
7. Get the first half and the second half of m, m = m1 | m2 and mr = total number of digits in m2
8. Get the first half and the second half of n, n = n1 | n2 and nr = total number of digits in n2
9. result = result + DC(m1, n1) * 10mr + nr
10. result = result + DC(m1, n2) * 10mr
11. result = result + DC(m2, n1) * 10nr
12. result = result + DC(m2, n2)
13. return result

แบบฝึกหัด จงหาผลคูณต่อไปนี้โดยใช้ทั้งสามวิธี
  1. 9834 * 985
  2. 51823 * 3475
  3. 82837 * 87364
รูปทั่วไปของ Divide-and-conquer คือ
DIVIDE-AND-CONQUER(x)
ข้อมูลเข้า x เป็นข้อมูลเข้า
ข้อมูลออก y เป็นผลลัพธ์ที่ต้องการ
1. If x is sufficiently small or simple then
2.     then return adhoc(x)
3. endif
4. For i = 1 to L do
5.     yi = DC(xi)
6.     recombine the yi's to obtain a solution y for x
7. endfor
8. return y

ปัญหาการค้นหาแบบทวิภาค (Binary search)
การค้นหาแบบนี้มักถูกใช้กับการค้นหาคำในพจนานุกรม เพราะว่า คำที่เก็บอยู่ในพจนานุกรมนั้นเรียงตามลำดับ วิธีการหลักคือ การทดสอบกับคำที่อยู่กึ่งกลางของข้อมูล แล้วเทียบว่าเจอคำนั้นหรือไม่ ถ้าเจอให้หยุดมิฉะนั้น เราจะตัดสินใจในการเลือกข้างของ ข้อมูลที่คำที่ต้องการค้นนั้นอยู่ โดยทิ้งข้อมูลอีกข้างที่คำนั้นไม่อยู่แน่นอน
เราอาจพิจารณาการค้นเชิงเส้นแบบง่าย ๆ คือ
SEQUENTIAL(T, x)
ข้อมูลเข้า T เป็นข้อมูลแบบแถวลำดับที่จะถูกค้น และ x คือคำที่ต้องการค้นใน T
ข้อมูลออก t เป็นดรรชนีใน T ที่บ่งบอกค่า x ถ้า x ไม่อยู่ใน T เราจะให้ t = -1

1. For t = 1 to length(T)
2.   if( T[t] == x ) then return t
3. endfor
4. return t = -1;
BINSEARCH(T, x)
ข้อมูลเข้า T เป็นข้อมูลแบบแถวลำดับที่จะถูกค้นโดยข้อมูลมีการเรียงตามลำดับ และ x คือคำที่ต้องการค้นใน T
ข้อมูลออก t เป็นดรรชนีใน T ที่บ่งบอกค่า x ถ้า x ไม่อยู่ใน T เราจะให้ t = -1
1. n = length(T)
2. If n = 0 or x > T[n]
3.     then return -1
4.     else return BINREC(T, 1, n, x)
5. endif
BINREC(T, i, j, x)
ข้อมูลเข้า T เป็นข้อมูลแบบแถวลำดับที่จะถูกค้น, i และ j คือดรรชนีของ T และ x คือคำที่ต้องการค้นใน T โดยที่ T[i-1] < x T[j]
ข้อมูลออก t เป็นดรรชนีใน T ที่บ่งบอกค่า x ถ้า x ไม่อยู่ใน T เราจะให้ t = -1
1.  If i = j 
2.     then if(x = T[i]) then return i
3.             else return -1
4.             endif
5. endif
6. k = (i+j)÷ 2
7. if x  T[k] 
8.    then BINREC(T, i, k, x)
9.    else BINREC(T, k+1, j, x)
10. endif
หรือเราสามารถเขียน การค้นหาแบบทวิภาค โดยใช้การวนซ้ำดังนี้
BINITER(T, x)
ข้อมูลเข้า T เป็นข้อมูลแบบแถวลำดับที่จะถูกค้น และ x คือคำที่ต้องการค้นใน T
ข้อมูลออก t เป็นดรรชนีใน T ที่บ่งบอกค่า x ถ้า x ไม่อยู่ใน T เราจะให้ t = -1
1. n = length(T)
2. if (x > T[n]) then return -1
3. i = 1; j = n
4. while i < j do {
5.     k = (i + j) ÷ 2
6.    if (x  T[k]) then
7.        then j = k;
8.       else i = k+1
9. endwhile
10. if (x != T[i]) then return -1
11. return i

การจัดลำดับข้อมูลแบบ Merge sort และ Quick sort
การจัดลำดับข้อมูลทั้งสองแบบใช้หลักการของการแบ่งเพื่อเอาชนะ เพราะว่า เราจะแบ่งรายการของสมาชิกออกเป็นสองส่วน หลังจากจัดลำดับเรียบร้อยแล้ว เราอาจนำมารวมกัน เพื่อให้ได้คำตอบของการจัดเรียงทุกข้อมูล

ปัญหาการคูณเมทริกซ์ (Matrix multiplication)
กำหนดให้ A และ B เป็นเมทริกซ์ขนาด n × n และ C เป็นเมทริกซ์ของผลคูณซึ่งนิยามว่า

Ci j = Ai k Bk j.
เราได้ว่าแต่ละค่าของ Ci j จะใช้เวลา O(n) ถ้าเราสมมติว่าการคูณและการบวกตัวเลขเป็น elementary operations แต่เรามีค่าของ Ci j อยู่ n2 ดังนั้นโดยการใช้นิยาม เราสามารถคำนวณเมทริกซ์ C โดย O(n3)
ปลายปี 1960s Strassen พบว่า เราสามารถลดจำนวนการคูณกันของตัวเลขในการคำนวณเมทริกซ์ผลคูณได้โดยใช้หลักการ divide-and-conquer โดยเริ่มต้นเราจะแสดงว่า การคูณกันของเมทริกซ์ขนาด 2 × 2 ใช้จำนวนการคูณน้อยกว่า 8 คือ
A = และ B =
พิจารณาการคำนวณของตัวเลขเจ็ดตัวนี้
m1 = (a2 1 + a2 2 - a1 1) (b2 2 - b1 2 + b1 1)
m2 = a1 1 b1 1
m3 = a1 2 b2 1
m4 = (a1 1 - a2 1) (b2 2 - b1 2)
m5 = (a2 1 + a2 2) (b1 2 - b1 1)
m6 = (a1 2 - a2 1 + a1 1 - a2 2) b2 2
m7 = a2 2 (b1 1 + b2 2 - b1 2 - b2 1)
เราพบว่าเราเพียงใช้การคูณเพียงเจ็ดครั้ง ซึ่งคำนวณ C ได้ดังนี้
C =

Home | Previous | Next


© Copyright by กรุง สินอภิรมย์สราญ