กำหนดการพลวัต
ในคณิตศาสตร์ วิทยาการคอมพิวเตอร์ และเศรษฐศาสตร์ กำหนดการพลวัต หรือ การเขียนโปรแกรมแบบไดนามิก (อังกฤษ: dynamic programming; ย่อว่า DP) เป็นระเบียบวิธีในการออกแบบขั้นตอนวิธีสำหรับแก้ปัญหาที่สามารถแบ่งออกเป็นปัญหาย่อยได้ โดยจัดเก็บคำตอบของปัญหาย่อยที่เคยคำนวณไว้เพื่อนำกลับมาใช้ใหม่ แทนการคำนวณปัญหาย่อยเดิมซ้ำหลายครั้ง[1][2]
ปัญหาที่เหมาะกับการใช้DPมักมีปัญหาย่อยที่ทับซ้อนกัน (overlapping subproblems) และมีโครงสร้างย่อยที่เหมาะสมที่สุด (optimal substructure) กล่าวคือ คำตอบของปัญหาใหญ่สามารถสร้างขึ้นจากคำตอบของปัญหาย่อยได้ วิธีนี้ใช้ได้ทั้งการแก้ปัญหาแบบบนลงล่าง (top-down) ซึ่งมักใช้ร่วมกับการจำ (memoization) และการแก้ปัญหาแบบล่างขึ้นบน (bottom-up) ซึ่งคำนวณคำตอบของปัญหาย่อยตามลำดับจากขนาดเล็กไปใหญ่
หลักการสำคัญของDPคือ เมื่อพบปัญหาย่อยหนึ่งแล้ว จะคำนวณและจัดเก็บคำตอบของปัญหาย่อยนั้นไว้ เมื่อพบปัญหาย่อยเดิมอีกครั้ง ก็สามารถนำคำตอบที่จัดเก็บไว้มาปรับใช้ได้โดยไม่ต้องคำนวณใหม่ การหลีกเลี่ยงการคำนวณซ้ำนี้ช่วยลดเวลาและทรัพยากรที่ใช้ในการแก้ปัญหาได้ในหลายกรณี โดยเฉพาะปัญหาที่มีปัญหาย่อยทับซ้อนกันเป็นจำนวนมาก
ประวัติ
[แก้]จุดกำเนิดในทฤษฎีการตัดสินใจ
[แก้]ก่อนคริสต์ทศวรรษ 1950 นักคณิตศาสตร์ใช้ความสัมพันธ์เวียนเกิด (recurrence relation) การคำนวณย้อนหลัง และแคลคูลัสของการแปรผัน (calculus of variations) แก้ปัญหาที่ประกอบด้วยการตัดสินใจหลายขั้นอยู่แล้ว อย่างไรก็ตาม วิธีเหล่านี้ยังไม่ได้รวมกันเป็นทฤษฎีทั่วไปสำหรับปัญหาที่การตัดสินใจในขั้นหนึ่งเปลี่ยนแปลงทางเลือกที่มีอยู่ในขั้นถัดไป ผลงานสำคัญของริชาร์ด เบลล์แมน (Richard Bellman) จึงไม่ใช่เพียงการเสนอสูตรเวียนเกิดสูตรใดสูตรหนึ่ง แต่เป็นการวางกรอบทั่วไปสำหรับอธิบายและแก้ กระบวนการตัดสินใจหลายขั้น (multistage decision process)[3]
เบลล์แมนเล่าย้อนหลังว่าเขาเริ่มศึกษาปัญหาการตัดสินใจหลายขั้นระหว่างทำงานที่แรนด์คอร์ปอเรชัน (RAND Corporation) ในฤดูร้อน ค.ศ. 1949 ตามคำแนะนำของเอ็ด แพกซ์สัน (Ed Paxson) ต่อมาในฤดูใบไม้ร่วง ค.ศ. 1950 เขาเริ่มใช้ชื่อ ไดนามิกโปรแกรมมิง (dynamic programming) สำหรับแนวคิดดังกล่าว[4] คำว่า โปรแกรมมิง ในที่นี้มิได้หมายถึงการเขียนโปรแกรมคอมพิวเตอร์ แต่ใช้ในความหมายของการจัดทำแผนหรือการกำหนดชุดการตัดสินใจ เช่นเดียวกับคำว่ากำหนดการเชิงเส้น (linear programming) ส่วนคำว่า ไดนามิก สื่อว่าปัญหามีหลายขั้นและเปลี่ยนแปลงไปตามเวลา[4][5]
เบลล์แมนตีพิมพ์บทความเรื่อง “On the Theory of Dynamic Programming” ใน ค.ศ. 1952 ซึ่งเป็นผลงานตีพิมพ์ระยะแรกที่วางแนวคิดของ DP ในรูปคณิตศาสตร์[6] ในปีถัดมา รายงานของแรนด์เรื่อง An Introduction to the Theory of Dynamic Programming อธิบายDP ว่าเป็นทฤษฎีคณิตศาสตร์สำหรับกระบวนการหลายขั้น ซึ่งผลของการดำเนินการก่อนหน้าสามารถนำมาใช้กำหนดการดำเนินการในอนาคตได้ รายงานดังกล่าวครอบคลุมทั้งกระบวนการแบบกำหนดแน่นอน (deterministic process) และกระบวนการเชิงเฟ้นสุ่ม (stochastic process)[7]
ใน ค.ศ. 1954 เบลล์แมนเผยแพร่บทความสำรวจ “The Theory of Dynamic Programming” ซึ่งจัดระบบแนวคิดพื้นฐาน การสร้างสมการเชิงฟังก์ชัน (functional equation) และการประยุกต์กับปัญหาหลายขั้น[8] ต่อมา หนังสือ Dynamic Programming ค.ศ. 1957 ได้รวบรวมทฤษฎีดังกล่าวอย่างเป็นระบบ ทั้งปัญหาการจัดสรรทรัพยากร การควบคุม สินค้าคงคลัง เกมหลายขั้น กระบวนการตัดสินใจมาร์คอฟ และความสัมพันธ์กับแคลคูลัสของการแปรผัน หนังสือเล่มนี้ทำให้ DP กลายเป็นสาขาสำคัญของการวิจัยดำเนินงาน (operations research) และทฤษฎีการควบคุม (control theory)[9]
หลักภาวะเหมาะที่สุดและสมการเบลล์แมน
[แก้]แนวคิดศูนย์กลางของวิธีนี้คือ หลักภาวะเหมาะที่สุด (principle of optimality) ซึ่งกล่าวโดยสรุปว่า เมื่อเลือกส่วนแรกของแผนที่เหมาะที่สุดไปแล้ว การตัดสินใจที่เหลือจะต้องเป็นแผนที่เหมาะที่สุดสำหรับสถานะใหม่ที่เกิดจากการตัดสินใจครั้งแรกด้วย[8][9] ตัวอย่างเช่น หากเส้นทางสั้นที่สุดจากเมือง ก ไปเมือง ง ผ่านเมือง ข แล้ว ส่วนของเส้นทางจากเมือง ข ไปเมือง ง ก็ต้องเป็นเส้นทางสั้นที่สุดจาก ข ไป ง เช่นกัน มิฉะนั้นย่อมสามารถแทนที่ส่วนนั้นด้วยเส้นทางที่สั้นกว่าและทำให้เส้นทางทั้งหมดสั้นลงได้
เบลล์แมนแทน “คำตอบที่ดีที่สุดนับจากสถานะปัจจุบันไปจนจบ” ด้วยฟังก์ชันค่า (value function) ให้ เป็นต้นทุนต่ำที่สุดที่ยังเหลืออยู่ เมื่อระบบอยู่ในสถานะ ณ ขั้นที่ ถ้าเลือกการกระทำ แล้วเสียต้นทุนทันที และเปลี่ยนไปเป็นสถานะ จะเขียนความสัมพันธ์ได้ว่า
โดย คือชุดการกระทำที่เลือกได้จากสถานะ สูตรนี้เรียกโดยทั่วไปว่าสมการเบลล์แมน (Bellman equation) ความหมายอย่างไม่เป็นทางการคือ
- ค่าที่ดีที่สุดจากจุดปัจจุบัน = ต้นทุนของการตัดสินใจครั้งนี้ + ค่าที่ดีที่สุดของปัญหาที่เหลือ
จึงไม่จำเป็นต้องพิจารณาแผนการทั้งหมดพร้อมกัน แต่พิจารณาการตัดสินใจครั้งถัดไปแล้วนำคำตอบของปัญหาส่วนที่เหลือมาใช้ วิธีคำนวณมักเริ่มจากสถานะสุดท้ายแล้วค่อยย้อนกลับมายังสถานะเริ่มต้น เรียกว่า การอุปนัยย้อนหลัง (backward induction) หรือ การเวียนเกิดย้อนหลัง (backward recursion)[9]
ตัวอย่างอย่างง่าย สมมุติว่าต้องเดินทางจาก ก ไป ง โดยมีเส้นทางและระยะทางดังนี้
- ก → ข มีระยะทาง 4
- ก → ค มีระยะทาง 2
- ข → ง มีระยะทาง 3
- ค → ง มีระยะทาง 6
เริ่มจากปลายทาง จะได้ เพราะเมื่อถึง ง แล้วไม่ต้องเดินทางต่อ จากนั้นคำนวณย้อนกลับเป็น
ดังนั้นเส้นทางที่สั้นที่สุดคือ ก → ข → ง มีระยะทางรวม 7 จุดสำคัญคือ เมื่อคำนวณ หรือ แล้ว สามารถเก็บค่านั้นไว้และนำกลับมาใช้ โดยไม่ต้องแก้ปัญหาเดิมซ้ำอีก
การแพร่เข้าสู่วิทยาการคอมพิวเตอร์
[แก้]ในบริบทดั้งเดิม DP เป็นวิธีทางคณิตศาสตร์สำหรับการตัดสินใจและการหาค่าเหมาะที่สุด ต่อมานักวิทยาการคอมพิวเตอร์นำแนวคิดเดียวกันมาใช้ออกแบบขั้นตอนวิธี โดยเรียกปัญหาที่คำตอบเหมาะที่สุดสามารถประกอบขึ้นจากคำตอบเหมาะที่สุดของปัญหาย่อยว่า มี โครงสร้างย่อยเหมาะที่สุด (optimal substructure) และเรียกกรณีที่ปัญหาย่อยเดิมปรากฏซ้ำหลายครั้งว่า มี ปัญหาย่อยทับซ้อน (overlapping subproblems)
หากใช้การเรียกซ้ำธรรมดา ปัญหาย่อยเดียวกันอาจถูกคำนวณซ้ำเป็นจำนวนมาก DP จึงเก็บคำตอบของแต่ละปัญหาย่อยไว้ การดำเนินการแบบบนลงล่าง (top-down) ที่เก็บผลของการเรียกซ้ำเรียกว่า การจำ (memoization) ส่วนการดำเนินการแบบล่างขึ้นบน (bottom-up) ที่คำนวณจากปัญหาเล็กไปหาปัญหาใหญ่เรียกว่า การจัดตาราง (tabulation) ทั้งสองแบบอาศัยความสัมพันธ์เวียนเกิดเดียวกัน ต่างกันที่ลำดับการคำนวณและการจัดเก็บผลลัพธ์[5]
ใน ค.ศ. 1957 เบลล์แมนเชื่อมDP กับกระบวนการตัดสินใจมาร์คอฟ (Markov decision process) ซึ่งอธิบายการตัดสินใจภายใต้ความไม่แน่นอนโดยใช้สถานะ การกระทำ ความน่าจะเป็นของการเปลี่ยนสถานะ และผลตอบแทน[10] กรอบนี้ต่อมากลายเป็นพื้นฐานของการควบคุมเชิงเฟ้นสุ่ม (stochastic control) การวางแผนทางเศรษฐศาสตร์ และการเรียนรู้แบบเสริมกำลัง (reinforcement learning)
ใน ค.ศ. 1962 เบลล์แมนเสนอวิธีDP สำหรับปัญหาพนักงานขายเดินทาง (travelling salesman problem)[11] ในปีเดียวกัน ไมเคิล เฮลด์ (Michael Held) และริชาร์ด คาร์ป (Richard Karp) เผยแพร่วิธีที่ได้ผลอย่างเป็นอิสระ โดยกำหนดสถานะจากเซตของเมืองที่เยี่ยมชมแล้วและเมืองปลายทางปัจจุบัน[12] วิธีดังกล่าวยังใช้เวลาแบบเลขชี้กำลัง แต่ลดจำนวนกรณีจากการไล่เรียงเส้นทางทุกแบบประมาณ เหลือประมาณ แสดงให้เห็นว่าDP อาจช่วยลดขนาดการค้นหาได้อย่างมาก แม้ไม่ทำให้ทุกปัญหากลายเป็นปัญหาที่แก้ได้ในเวลาพหุนามก็ตาม
แนวคิดนี้แพร่ไปยังสาขาอื่นอย่างรวดเร็ว ใน ค.ศ. 1967 แอนดรูว์ วิเทอร์บี (Andrew Viterbi) เสนอขั้นตอนวิธีวิเทอร์บี (Viterbi algorithm) สำหรับการถอดรหัสรหัสคอนโวลูชัน (convolutional code) โดยเก็บเส้นทางบางส่วนที่ดีที่สุดสำหรับแต่ละสถานะของระบบ[13] ต่อมาขั้นตอนวิธีนี้ถูกใช้ในโทรคมนาคม การรู้จำเสียง และแบบจำลองมาร์คอฟซ่อนเร้น (hidden Markov model)
ใน ค.ศ. 1970 ซอล นีเดิลแมน (Saul Needleman) และคริสเตียน วุนช์ (Christian Wunsch) เผยแพร่ขั้นตอนวิธีนีเดิลแมน–วุนช์ (Needleman–Wunsch algorithm) สำหรับเปรียบเทียบลำดับกรดอะมิโนของโปรตีน โดยแทนปัญหาย่อยด้วยช่องต่าง ๆ ในตารางสองมิติและคำนวณค่าที่ดีที่สุดจากช่องข้างเคียง[14] งานนี้ทำให้DP กลายเป็นเครื่องมือพื้นฐานของชีวสารสนเทศศาสตร์ (bioinformatics) โดยเฉพาะการจัดแนวลำดับดีเอ็นเอ อาร์เอ็นเอ และโปรตีน
ข้อจำกัดและพัฒนาการสมัยใหม่
[แก้]ประสิทธิภาพของDP ขึ้นอยู่กับจำนวนสถานะที่ต้องคำนวณ หากระบบมีตัวแปรสถานะจำนวนมาก จำนวนสถานะอาจเพิ่มขึ้นอย่างรวดเร็ว เช่น ถ้ามีตัวแปร ตัว และแบ่งค่าของแต่ละตัวออกเป็น ระดับ ตารางอาจมีขนาดถึง เบลล์แมนเรียกปัญหานี้ว่า คำสาปของมิติ (curse of dimensionality)[15] ข้อจำกัดดังกล่าวนำไปสู่การพัฒนาวิธีประมาณค่าฟังก์ชันค่า การรวมสถานะ และDP โดยประมาณ (approximate dynamic programming)
ตั้งแต่คริสต์ทศวรรษ 1980 เป็นต้นมา สมการเบลล์แมนกลายเป็นพื้นฐานส่วนหนึ่งของการเรียนรู้แบบเสริมกำลัง โดยระบบเรียนรู้ค่าของสถานะหรือการกระทำจากประสบการณ์ แทนที่จะคำนวณจากแบบจำลองที่ทราบล่วงหน้า ตัวอย่างสำคัญคือคิวเลิร์นนิง (Q-learning) ซึ่งคริสโตเฟอร์ วัตคินส์ (Christopher Watkins) และปีเตอร์ เดย์ยัน (Peter Dayan) อธิบายว่าเป็นวิธีเพิ่มค่าทีละขั้นสำหรับDP และพิสูจน์การลู่เข้าภายใต้เงื่อนไขที่กำหนดใน ค.ศ. 1992[16] DP จึงยังคงเป็นรากฐานร่วมของการหาค่าเหมาะที่สุด ทฤษฎีการควบคุม ปัญญาประดิษฐ์ เศรษฐศาสตร์ และขั้นตอนวิธีสมัยใหม่[17]
ภาพรวม
[แก้]
DP ในการเขียนโปรแกรมคอมพิวเตอร์
[แก้]ในวิทยาการคอมพิวเตอร์ DP เป็นเทคนิคการออกแบบขั้นตอนวิธีที่แบ่งปัญหาออกเป็นปัญหาย่อย บันทึกคำตอบของปัญหาย่อยไว้ และนำคำตอบเหล่านั้นกลับมาใช้แทนการคำนวณใหม่ ปัญหาการหาค่าเหมาะที่สุดที่เหมาะกับเทคนิคนี้มักมีลักษณะสำคัญสองประการ ได้แก่ โครงสร้างย่อยที่เหมาะที่สุด (optimal substructure) และ ปัญหาย่อยที่ทับซ้อนกัน (overlapping subproblems)[18] อย่างไรก็ตาม DP มิได้จำกัดอยู่เฉพาะปัญหาการหาค่าเหมาะที่สุดเท่านั้น แต่ยังใช้กับปัญหาการนับ การตรวจสอบว่ามีคำตอบหรือไม่ และการคำนวณความน่าจะเป็นได้ด้วย
โครงสร้างย่อยที่เหมาะที่สุด หมายความว่า คำตอบที่เหมาะที่สุดของปัญหาทั้งหมดประกอบด้วยคำตอบที่เหมาะที่สุดของปัญหาย่อยบางปัญหา คุณสมบัตินี้มักแสดงด้วยความสัมพันธ์เวียนเกิด (recurrence relation) ซึ่งระบุว่าคำตอบของปัญหาขนาดใหญ่สามารถคำนวณจากคำตอบของปัญหาที่เล็กกว่าได้อย่างไร
ตัวอย่างเช่น กำหนดกราฟ และให้ เป็นเส้นทางสั้นที่สุด (shortest path) จากจุดยอด ไปยังจุดยอด ถ้าจุดยอด อยู่บนเส้นทาง แล้ว ส่วนของเส้นทางจาก ไปยัง และส่วนจาก ไปยัง จะต้องเป็นเส้นทางสั้นที่สุดระหว่างจุดยอดคู่ดังกล่าวด้วย มิฉะนั้นย่อมสามารถแทนส่วนใดส่วนหนึ่งด้วยเส้นทางที่สั้นกว่า และทำให้เส้นทางจาก ไปยัง สั้นลงได้ ดังนั้นจึงมีความสัมพันธ์ว่า
เมื่อ อยู่บนเส้นทางสั้นที่สุดจาก ไปยัง แนวคิดเรื่องโครงสร้างย่อยนี้เป็นพื้นฐานของขั้นตอนวิธีหาเส้นทางสั้นที่สุดหลายขั้นตอนวิธี เช่น ขั้นตอนวิธีเบลล์แมน–ฟอร์ดและขั้นตอนวิธีฟลอยด์–วอร์แชลล์ แม้ขั้นตอนวิธีทั้งสองจะกำหนดปัญหาย่อยและความสัมพันธ์เวียนเกิดแตกต่างกันก็ตาม
DP แตกต่างจากการแบ่งแยกและเอาชนะ (divide and conquer) ตรงที่ปัญหาย่อยของDP มักทับซ้อนกัน กล่าวคือ ปัญหาย่อยเดียวกันปรากฏซ้ำในหลายส่วนของการคำนวณ ส่วนขั้นตอนวิธีแบบแบ่งแยกและเอาชนะ เช่น ควิกซอร์ต (quicksort) และการเรียงลำดับแบบผสาน (merge sort) มักแบ่งข้อมูลออกเป็นปัญหาย่อยที่แยกจากกัน จึงไม่จำเป็นต้องบันทึกคำตอบเพื่อหลีกเลี่ยงการแก้ปัญหาย่อยเดิมซ้ำ

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

การนำ DP ไปใช้ในโปรแกรมมีสองแนวทางหลัก ได้แก่
- แบบบนลงล่าง (top-down) เริ่มจากปัญหาเดิมแล้วใช้การเรียกซ้ำ (recursion) เพื่อแก้ปัญหาย่อย เมื่อคำนวณคำตอบของปัญหาย่อยครั้งแรกแล้ว จะบันทึกคำตอบไว้ในตารางหรือแคช หากพบปัญหาย่อยเดิมอีกครั้ง โปรแกรมจะอ่านคำตอบที่บันทึกไว้แทนการคำนวณใหม่ วิธีบันทึกผลของฟังก์ชันตามอาร์กิวเมนต์ที่ได้รับเรียกว่า เมโมอิเซชัน (memoization)[19]
- แบบล่างขึ้นบน (bottom-up) เริ่มคำนวณจากกรณีฐานหรือปัญหาย่อยขนาดเล็กที่สุด แล้วค่อยใช้คำตอบเหล่านั้นสร้างคำตอบของปัญหาที่ใหญ่ขึ้น วิธีนี้มักเรียกว่า การจัดตาราง (tabulation) เพราะค่าของปัญหาย่อยมักถูกบันทึกลงในตารางตามลำดับที่กำหนดไว้ล่วงหน้า
ตัวอย่างเช่น การคำนวณจำนวนฟีโบนัชชีแบบล่างขึ้นบนเริ่มจาก และ แล้วคำนวณ ตามลำดับ เนื่องจากการคำนวณค่าใหม่ต้องใช้เพียงสองค่าก่อนหน้า จึงสามารถลดหน่วยความจำเสริมจาก เหลือ ได้โดยเก็บไว้เฉพาะสองค่าล่าสุด
ภาษาโปรแกรมและไลบรารีบางชนิดมีเครื่องมือช่วยทำเมโมอิเซชันหรือการจัดตาราง เช่น มอดูล Memoize ของภาษาเพิร์ล เดคอเรเตอร์ functools.cache และ functools.lru_cache ของภาษาไพทอน และการจัดตาราง (tabling) ในระบบภาษาโปรล็อกบางระบบ อย่างไรก็ตาม เครื่องมือเหล่านี้โดยทั่วไปต้องได้รับการประกาศหรือเรียกใช้โดยผู้เขียนโปรแกรม มิได้ทำเมโมอิเซชันให้กับฟังก์ชันทุกฟังก์ชันโดยอัตโนมัติ[20][21][22]
ในการเขียนโปรแกรม ภาษาโปรแกรมและระบบบางชนิดมีเครื่องมือช่วยทำเมโมอิเซชัน (memoization) โดยผู้เขียนโปรแกรมต้องประกาศหรือเรียกใช้เครื่องมือนั้นกับฟังก์ชันที่ต้องการ ตัวอย่างเช่น ระบบภาษาโปรล็อกบางระบบอย่างเอสดับเบิลยูไอ-โปรล็อก (SWI-Prolog) รองรับการจัดตาราง (tabling) ซึ่งบันทึกคำตอบของภาคแสดง (predicate) และนำกลับมาใช้เพื่อหลีกเลี่ยงการคำนวณซ้ำ[23] ส่วนภาษาเจมีตัวดำเนินการ M. ซึ่งเก็บอาร์กิวเมนต์และผลลัพธ์ของฟังก์ชันไว้เพื่อนำกลับมาใช้[24] นอกจากนี้ ไลบรารีมาตรฐานของบางภาษายังมีเครื่องมือสำหรับเมโมอิเซชัน เช่น มอดูล Memoize ของภาษาเพิร์ล[25] และเดคอเรเตอร์ (decorator) functools.cache กับ functools.lru_cache ของภาษาไพทอน[26] เครื่องมือเหล่านี้ไม่ได้ทำเมโมอิเซชันให้แก่ฟังก์ชันทั้งหมดโดยอัตโนมัติ แต่ต้องได้รับการระบุหรือเรียกใช้อย่างชัดเจนในโปรแกรม
อ้างอิง
[แก้]- ↑ Dasgupta, Sanjoy; Papadimitriou, Christos H.; Vazirani, Umesh V. Algorithms. p. 173.
- ↑ Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford (2009). Introduction to Algorithms (3rd ed.). Cambridge, Massachusetts: MIT Press. p. 359. ISBN 978-0-262-03384-8.
- ↑ Assad, Arjang A. (2011). "Richard E. Bellman". ใน Assad, Arjang A.; Gass, Saul I. (บ.ก.). Profiles in Operations Research: Pioneers and Innovators. International Series in Operations Research & Management Science (ภาษาอังกฤษ). Vol. 147. New York: Springer. pp. 415–445. doi:10.1007/978-1-4419-6281-2_23. ISBN 978-1-4419-6280-5.
- 1 2 Dreyfus, Stuart E. (2002). "Richard Bellman on the Birth of Dynamic Programming". Operations Research (ภาษาอังกฤษ). 50 (1): 48–51. doi:10.1287/opre.50.1.48.17791. สืบค้นเมื่อ 2026-07-15.
- 1 2 Eddy, Sean R. (2004). "What is dynamic programming?". Nature Biotechnology (ภาษาอังกฤษ). 22 (7): 909–910. doi:10.1038/nbt0704-909. สืบค้นเมื่อ 2026-07-15.
- ↑ Bellman, Richard (1952-08-15). "On the Theory of Dynamic Programming". Proceedings of the National Academy of Sciences of the United States of America (ภาษาอังกฤษ). 38 (8): 716–719. doi:10.1073/pnas.38.8.716. สืบค้นเมื่อ 2026-07-15.
- ↑ Bellman, Richard E. (1953). An Introduction to the Theory of Dynamic Programming (Report) (ภาษาอังกฤษ). Santa Monica, California: RAND Corporation. สืบค้นเมื่อ 2026-07-15.
- 1 2 Bellman, Richard (1954). "The Theory of Dynamic Programming". Bulletin of the American Mathematical Society (ภาษาอังกฤษ). 60 (6): 503–515. doi:10.1090/S0002-9904-1954-09848-8. สืบค้นเมื่อ 2026-07-15.
- 1 2 3 Bellman, Richard E. (1957). Dynamic Programming (ภาษาอังกฤษ). Princeton, New Jersey: Princeton University Press.
- ↑ Bellman, Richard (1957). "A Markovian Decision Process". Journal of Mathematics and Mechanics (ภาษาอังกฤษ). 6 (5): 679–684. doi:10.1512/iumj.1957.6.56038.
- ↑ Bellman, Richard (1962). "Dynamic Programming Treatment of the Travelling Salesman Problem". Journal of the ACM (ภาษาอังกฤษ). 9 (1): 61–63. doi:10.1145/321105.321111.
- ↑ Held, Michael; Karp, Richard M. (1962). "A Dynamic Programming Approach to Sequencing Problems". Journal of the Society for Industrial and Applied Mathematics (ภาษาอังกฤษ). 10 (1): 196–210. doi:10.1137/0110015. สืบค้นเมื่อ 2026-07-15.
- ↑ Viterbi, Andrew J. (1967-04). "Error Bounds for Convolutional Codes and an Asymptotically Optimum Decoding Algorithm". IEEE Transactions on Information Theory (ภาษาอังกฤษ). 13 (2): 260–269. doi:10.1109/TIT.1967.1054010.
{{cite journal}}: ตรวจสอบค่าวันที่ใน:|date=(help) - ↑ Needleman, Saul B.; Wunsch, Christian D. (1970-03-28). "A General Method Applicable to the Search for Similarities in the Amino Acid Sequence of Two Proteins". Journal of Molecular Biology (ภาษาอังกฤษ). 48 (3): 443–453. doi:10.1016/0022-2836(70)90057-4. สืบค้นเมื่อ 2026-07-15.
- ↑ Bellman, Richard E. (1961). Adaptive Control Processes: A Guided Tour (ภาษาอังกฤษ). Princeton, New Jersey: Princeton University Press.
- ↑ Watkins, Christopher J. C. H.; Dayan, Peter (1992). "Q-learning". Machine Learning (ภาษาอังกฤษ). 8 (3–4): 279–292. doi:10.1007/BF00992698.
- ↑ Sutton, Richard S.; Barto, Andrew G. (2018). Reinforcement Learning: An Introduction (ภาษาอังกฤษ) (2 ed.). Cambridge, Massachusetts: MIT Press. ISBN 978-0-262-03924-6. สืบค้นเมื่อ 2026-07-15.
- 1 2 Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford (2009). Introduction to Algorithms (ภาษาอังกฤษ) (3 ed.). Cambridge, Massachusetts: MIT Press. pp. 359–386. ISBN 978-0-262-03384-8.
- ↑ Michie, Donald (1968-04-06). ""Memo" Functions and Machine Learning". Nature (ภาษาอังกฤษ). 218 (5136): 19–22. doi:10.1038/218019a0.
- ↑ "Memoize — Make functions faster by trading space for time". Perldoc (ภาษาอังกฤษ). สืบค้นเมื่อ 2026-07-15.
- ↑ "functools — Higher-order functions and operations on callable objects". Python Documentation (ภาษาอังกฤษ). Python Software Foundation. สืบค้นเมื่อ 2026-07-15.
- ↑ "Example 1: using tabling for memoizing". SWI-Prolog Reference Manual (ภาษาอังกฤษ). สืบค้นเมื่อ 2026-07-15.
- ↑ "Tabled execution (SLG resolution)". SWI-Prolog Reference Manual (ภาษาอังกฤษ). สืบค้นเมื่อ 2026-07-15.
- ↑ "M. Memo". J Dictionary (ภาษาอังกฤษ). Jsoftware. สืบค้นเมื่อ 2026-07-15.
- ↑ "Memoize — Make functions faster by trading space for time". Perldoc (ภาษาอังกฤษ). สืบค้นเมื่อ 2026-07-15.
- ↑ "functools — Higher-order functions and operations on callable objects". Python Documentation (ภาษาอังกฤษ). Python Software Foundation. สืบค้นเมื่อ 2026-07-15.