ผลต่างระหว่างรุ่นของ "204512/บรรยาย 9"

จาก Theory Wiki
ไปยังการนำทาง ไปยังการค้นหา
แถว 42: แถว 42:
 
สังเกตว่ามันมีกรณีซ้ำซ้อนเกิดขึ้น
 
สังเกตว่ามันมีกรณีซ้ำซ้อนเกิดขึ้น
  
F[0]F[1]1
+
F[0]<-F[1]<=1<br/>
For i=2 to n do
+
<br/>
F[i]F[i-1] + F[i-2]
+
For i=2 to n do<br/>
Return F[n]
+
    F[i]<-F[i-1] + F[i-2]<br/>
 +
Return F[n]<br/>
  
 
นั่นคือ ถ้าอยากรู้ f(i) ต้องรู้ f(i-1), f(i-2)
 
นั่นคือ ถ้าอยากรู้ f(i) ต้องรู้ f(i-1), f(i-2)
แถว 71: แถว 72:
  
 
เราสามารถหาโดยไม่ต้องทำ recursive ก็ได้ โดยเรา evaluate ไปในทิศทางที่ขึ้นต่อกันเรื่อยๆ evaluate ด้วยลำดับที่เราเรียกว่า tropical order
 
เราสามารถหาโดยไม่ต้องทำ recursive ก็ได้ โดยเรา evaluate ไปในทิศทางที่ขึ้นต่อกันเรื่อยๆ evaluate ด้วยลำดับที่เราเรียกว่า tropical order
ถ้าเรียงลำดับตาม tolopical order (คือเป็น order ที่ edge ชี้จากโหนดน้อยมาก)
+
ถ้าเรียงลำดับตาม tolopical order (คือเป็น order ที่ edge ชี้จากโหนดน้อย->มาก)<br/>
 
S = <math>v_0</math>, <math>v_1</math>, <math>v_2</math>, <math>v_3</math>, … , <math>v_n</math>
 
S = <math>v_0</math>, <math>v_1</math>, <math>v_2</math>, <math>v_3</math>, … , <math>v_n</math>
 
+
<br/>
Foreach vi, D(v1) infinity
+
Foreach vi, D(v1) <- infinity<br/>
D(v0) 0
+
D(v0) <- 0<br/>
For I = 1,…,n:
+
For I = 1,…,n:<br/>
D(vi) = min [D(Vj) + l(vj,vi)]
+
D(vi) = min [D(Vj) + l(vj,vi)]<br/>
 
                       Vj: (Vj, Vi) E E
 
                       Vj: (Vj, Vi) E E
  
ขั้นตอนการแก้ปัญหา dynamic programming
+
ขั้นตอนการแก้ปัญหา dynamic programming<br/>
1. เขียน recurrence (เริ่มต้นนิยามปัญหาย่อย)
+
1. เขียน recurrence (เริ่มต้นนิยามปัญหาย่อย)<br/>
2. หาลำดับเพื่อ evaluate
+
2. หาลำดับเพื่อ evaluate<br/>
3. เขียน pseudo code
+
3. เขียน pseudo code<br/>
  
  
แถว 108: แถว 109:
  
 
ถ้าถามต่ออีกว่า เราจะรู้ได้หรือไม่ ว่าใช้เหรียญอะไรไปบ้าง? วิธีการคือ เราจะเก็บ pointer ไว้ เพื่อดูว่าค่าผลรวมได้มาจากการรวมเหรียญไหนไปบ้าง
 
ถ้าถามต่ออีกว่า เราจะรู้ได้หรือไม่ ว่าใช้เหรียญอะไรไปบ้าง? วิธีการคือ เราจะเก็บ pointer ไว้ เพื่อดูว่าค่าผลรวมได้มาจากการรวมเหรียญไหนไปบ้าง
 
+
</math>
  
 
[[Example]]
 
[[Example]]
  
มีถุงความจุเป็น L หน่วย
+
มีถุงความจุเป็น L หน่วย<br/>
มีสินค้า k ประเภท
+
มีสินค้า k ประเภท<br/>
ประเภทที่ i, มีน้ำหนัก wi หน่วย
+
ประเภทที่ i, มีน้ำหนัก wi หน่วย<br/>
มีมูลค่า vi หน่วย
+
มีมูลค่า vi หน่วย<br/>
 
+
<br/>
ให้หาสินค้าใส่ถุงโดย 1. ความจุรวม = L
+
ให้หาสินค้าใส่ถุงโดย<br/>
2. มูลค่ารวมมากที่สุด
+
1. ความจุรวม = L<br/>
 
+
2. มูลค่ารวมมากที่สุด<br/>
เลือกสินค้าที่ i มา 1 ชิ้น จะได้ว่า
+
<br/>
 +
เลือกสินค้าที่ i มา 1 ชิ้น จะได้ว่า<br/>
 
1. P(i) = max P(i-wj) + Vj  j:wj <= i
 
1. P(i) = max P(i-wj) + Vj  j:wj <= i
 
2. คำตอบคือ max P(i)
 
2. คำตอบคือ max P(i)
 
                   i: i <= L
 
                   i: i <= L
A(i) = arg min P(i-wj) + Vj
+
A(i) = arg min P(i-wj) + Vj<br/>
อัลกอริทึมนี้ จะรันอยู่ในเวลา O(kL)
+
<br/>
คำตอบนี้สำหรับปัญหาที่มี จำนวนสินค้าได้ไม่อั้น
+
อัลกอริทึมนี้ จะรันอยู่ในเวลา O(kL)<br/>
แต่สำหรับสินค้าที่มี จำนวนกัด เราจะแก้ไขปัญหาได้อย่างไร  
+
คำตอบนี้สำหรับปัญหาที่มี จำนวนสินค้าได้ไม่อั้น<br/>
ปัญหาลักษณะนี้เราเรียกว่า Knapsack problem
+
แต่สำหรับสินค้าที่มี จำนวนกัด เราจะแก้ไขปัญหาได้อย่างไร<br/>
 +
ปัญหาลักษณะนี้เราเรียกว่า Knapsack problem<br/>
 +
 
 +
<br/>
 +
[[Knapstack]]<br/>
 +
ถุงมีความจุ L หน่วย<br/>
 +
มีของ k ชิ้น<br/>
 +
ชิ้นที่ i หนัก <math>w_{i}</math>, มีมูลค่า <math>v_{L}</math><br/>
 +
<br/>
 +
ต้องการหาเซตของ ของ ที่<br/>
 +
(1) น้ำหนักรวมของ ของ รวมไม่เกิน L<br/>
 +
(2) มีมูลค่ารวมมากที่สุด<br/>
 +
*ต้องจัดลำดัับการหยิบให้ดี เพราะ ของแต่ละแบบมีชิ้นเดียว<br/>
 +
'''hint:''' มีตัวแปร 2 ตัว<br/>
 +
<br/>
 +
[[sol]]<br/> 
 +
จัดการหยิบของให้มีลำดับ<br/>
 +
        เอาของชิ้นที่ 1 -> หยิบ
 +
                    -> ไม่่หยิบ
 +
        เอาของชิ้นที่ 2 -> หยิบ
 +
                    -> ไม่่หยิบ
 +
        เอาของชิ้นที่ 3 -> หยิบ
 +
                    -> ไม่่หยิบ
 +
                  .
 +
                  .
 +
                  .
 +
        เอาของชิ้นที่ n -> หยิบ
 +
                    -> ไม่่หยิบ
 +
ให้<br/>
 +
<math>A(i,j)</math> แทนมูลค่ามากที่สุดที่ทำได้เมื่อน้ำหนักรวม = i และใช้ของไม่เกินชิ้นที่ j<br/>         
 +
<math>A(i,j) = max
 +
\begin{cases}
 +
A(i,j-1) \\
 +
v_{j}+A(i-w_{j},j-1),  & \mbox{if } i >= w_{j}
 +
\end{cases}</math>
 +
ตาราง L??????

รุ่นแก้ไขเมื่อ 07:09, 15 สิงหาคม 2550

Dynamic Programming

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

DP1.jpg

คำตอบคือ สามารถเลือกได้ แบบ หรือ แบบ

C(m,n) = C(m-1, n) + C(m,n-1)

C(0,0) เลือกได้ 1 วิธี

C(x,y) = 0 ถ้า x<0 หรือ y<0

ในกรณีที่มีการ block เส้นทาง เราอาจจะเขียน pseudo code ได้ ให้ recursive ไปที่จุดที่ col-1, row-1 ไปเรื่อยๆ

วิธีหนึ่งที่ใช้หาเส้นทาง

DP2.jpg

วิธีนี้เราจะทำการมองไปที่ทุกจุด โดยค่าที่แต่ละจุดเกิดจากผลรวมน้ำหนักของโหนดก่อนหน้า ดังนั้นวิธีนี้ใช้เวลาเป็น O(mn)

Dynamic programming คือการคำนวนมาก่อนเพื่อหาผลเฉลย

Example

Function revolenchy

F(0) = F(1) = 1

F(1) = F(i-1) + F(i-2) เมื่อ i>1

สังเกตว่ามันมีกรณีซ้ำซ้อนเกิดขึ้น

F[0]<-F[1]<=1

For i=2 to n do
F[i]<-F[i-1] + F[i-2]
Return F[n]

นั่นคือ ถ้าอยากรู้ f(i) ต้องรู้ f(i-1), f(i-2) DP3.jpg


Shortest path บน DAG (Directed Acyclic Graph)

เราหา shortest path อย่างไร จาก st

t อาจมีตัวติดกันมากมาย shortest path ที่มาจาก ts ได้ ถ้ามีนผ่าน , , พวกนี้ต้องเป็น shortest path ด้วยเช่นเดียวกัน

ถ้ามองแบบ recursive เราจะค่อยคลี่ออกแล้วมองปัญหาย่อยๆ

DP4.jpg


เราสามารถหาโดยไม่ต้องทำ recursive ก็ได้ โดยเรา evaluate ไปในทิศทางที่ขึ้นต่อกันเรื่อยๆ evaluate ด้วยลำดับที่เราเรียกว่า tropical order ถ้าเรียงลำดับตาม tolopical order (คือเป็น order ที่ edge ชี้จากโหนดน้อย->มาก)
S = , , , , … ,
Foreach vi, D(v1) <- infinity
D(v0) <- 0
For I = 1,…,n:
D(vi) = min [D(Vj) + l(vj,vi)]

                     Vj: (Vj, Vi) E E

ขั้นตอนการแก้ปัญหา dynamic programming
1. เขียน recurrence (เริ่มต้นนิยามปัญหาย่อย)
2. หาลำดับเพื่อ evaluate
3. เขียน pseudo code


Example

ถ้าเรามีเหรียญ 3, 5 บาท เราจะประกอบเหรียญให้เป็นเงินจำนวนไม่เกิน 100 บาท ได้กี่วิธี (ใช้เหรียญกี่เหรียญก็ได้)

เราอาจจะ plot เป็นตารางดังนี้

ตารางนี้เราทำการเก็บว่า ค่าไหนที่เกิดจากผลรวมของตัวมันบ้าง ซึ่งอาจจะให้ผลดีขึ้นถ้าเราเก็บด้วยว่าเราใช้เหรียญไปกี่เหรียญ

Example P(i) แทนจำนวนเหรียญที่เราใช้แล้วรวมกันได้ i บาท

ตัวอย่างนี้เราสามารถหาเหรียญที่ใช้น้อยที่สุดได้

ถ้าถามต่ออีกว่า เราจะรู้ได้หรือไม่ ว่าใช้เหรียญอะไรไปบ้าง? วิธีการคือ เราจะเก็บ pointer ไว้ เพื่อดูว่าค่าผลรวมได้มาจากการรวมเหรียญไหนไปบ้าง </math>

Example

มีถุงความจุเป็น L หน่วย
มีสินค้า k ประเภท
ประเภทที่ i, มีน้ำหนัก wi หน่วย
มีมูลค่า vi หน่วย

ให้หาสินค้าใส่ถุงโดย
1. ความจุรวม = L
2. มูลค่ารวมมากที่สุด

เลือกสินค้าที่ i มา 1 ชิ้น จะได้ว่า
1. P(i) = max P(i-wj) + Vj j:wj <= i 2. คำตอบคือ max P(i)

                 i: i <= L

A(i) = arg min P(i-wj) + Vj

อัลกอริทึมนี้ จะรันอยู่ในเวลา O(kL)
คำตอบนี้สำหรับปัญหาที่มี จำนวนสินค้าได้ไม่อั้น
แต่สำหรับสินค้าที่มี จำนวนกัด เราจะแก้ไขปัญหาได้อย่างไร
ปัญหาลักษณะนี้เราเรียกว่า Knapsack problem


Knapstack
ถุงมีความจุ L หน่วย
มีของ k ชิ้น
ชิ้นที่ i หนัก , มีมูลค่า

ต้องการหาเซตของ ของ ที่
(1) น้ำหนักรวมของ ของ รวมไม่เกิน L
(2) มีมูลค่ารวมมากที่สุด

  • ต้องจัดลำดัับการหยิบให้ดี เพราะ ของแต่ละแบบมีชิ้นเดียว

hint: มีตัวแปร 2 ตัว

sol
จัดการหยิบของให้มีลำดับ

        เอาของชิ้นที่ 1 -> หยิบ
                   -> ไม่่หยิบ
        เอาของชิ้นที่ 2 -> หยิบ
                   -> ไม่่หยิบ
        เอาของชิ้นที่ 3 -> หยิบ
                   -> ไม่่หยิบ
                 .
                 .
                 .
        เอาของชิ้นที่ n -> หยิบ
                   -> ไม่่หยิบ

ให้
แทนมูลค่ามากที่สุดที่ทำได้เมื่อน้ำหนักรวม = i และใช้ของไม่เกินชิ้นที่ j
ตาราง L??????