गतिक प्रोग्रामिंग

गतिक प्रोग्रामिंग गणितीय अनुकूलनन और कंप्यूटर प्रोग्रामिंग विधि है। जिसे 1950 के दशक में रिचर्ड बेलमैन द्वारा विकसित किया गया था और अंतरिक्ष अभियांत्रिकी से लेकर अर्थशास्त्र तक कई क्षेत्रों में इसका उपयोग किया गया है।

इस प्रकार दोनों संदर्भों में इसके द्वारा जटिल समस्या को पुनरावर्ती विधियों से सरल उप-समस्याओं में तोड़कर सरल बनाने के लिए संदर्भित किया जाता है। जबकि कुछ निर्णय समस्याओं को इस प्रकार अलग नहीं किये जाते हैं, ऐसे निर्णय जो समय में कई बिंदुओं का प्रसार करते हैं, अधिकांशतः पुनरावर्ती रूप से अलग हो जाते हैं। इस प्रकार कंप्यूटर विज्ञान में, यदि किसी समस्या को उप-समस्याओं में तोड़कर और फिर पुनरावर्ती रूप से उप-समस्याओं का इष्टतम समाधान ढूंढकर हल किया जाता है, तो इसे 'इष्टतम उप-संरचना' कहा जाता है।

यदि उप-समस्याओं को पुनरावर्ती रूप से बड़ी समस्याओं के अंदर संयोजिक किया जा सकता है, जिससे कि गतिक प्रोग्रामिंग विधियों को उपयोग किया जा सके, तो बड़ी समस्या के मान और उप-समस्याओं के मानों के बीच संबंध होता है। अनुकूलन साहित्य में इस संबंध को बेलमैन समीकरण कहा जाता है।

गणितीय अनुकूलन
गणितीय अनुकूलन के संदर्भ में, गतिक प्रोग्रामिंग सामान्यतः समय के साथ निर्णय चरणों के अनुक्रम में इसे तोड़कर निर्णय को सरल बनाने के लिए संदर्भित करता है। यह मूल्य कार्यों 'v1' के अनुक्रम को परिभाषित करके किया जाता है, i2, ..., in y को 1 से n तक के समय में प्रणाली के 'चर अवस्था' का प्रतिनिधित्व करने वाले तर्क के रूप में निर्दिष्ट किया जा सकता हैं। vn (y) की परिभाषा के अंतिम समय पर स्थिति y में प्राप्त मान को निर्गत करना सरल होता हैं है। इस प्रकार vi मान को पहले के समय में i = n −1, n − 2, ..., 2, 1 को बेलमैन समीकरण नामक पुनरावर्तन संबंध का उपयोग करके पीछे की ओर कार्य करके पाया जाता है। i = 2, ..., n, vi&minus;1 के लिए किसी भी अवस्था में y की गणना Vi द्वारा की जाती है इस प्रकार समय i − 1 और फ़ंक्शन Vi पर किसी निर्णय से होने वाले लाभ के साधारण फ़ंक्शन (सामान्यतः योग) को अधिकतम मान प्राप्त करके यदि यह निर्णय किया जाता है तो इस प्रणाली की नई स्थिति में इसे उपयोग किया जा सकता हैं। चूंकि vi को पहले से ही आवश्यक स्थितियों के लिए गणना की जा चुकी है, उपरोक्त ऑपरेशन के उत्पाद के लिए vi&minus;1 इन स्थितियों के लिए सहायक हैं। इस प्रकार अंत में प्राप्त v1 प्रणाली की प्रारंभिक अवस्था में इष्टतम समाधान का मान प्राप्त करता है। इसलिए पहले से की गई गणनाओं को वापस ट्रैक करके, निर्णय चर के इष्टतम मान को क्रमशः पुनर्प्राप्त किया जाता है।

नियंत्रण सिद्धांत
नियंत्रण सिद्धांत में, स्वीकार्य नियंत्रण खोजने के लिए सामान्य समस्या $$\mathbf{u}^{\ast}$$है, जो $$\dot{\mathbf{x}}(t) = \mathbf{g} \left( \mathbf{x}(t), \mathbf{u}(t), t \right)$$ प्रणाली का कारण बनता है, इस प्रकार स्वीकार्य किए जाने वाले प्रक्षेपवक्र का पालन करने के लिए $$\mathbf{x}^{\ast}$$ को निरंतर समय अंतराल पर $$t_{0} \leq t \leq t_{1}$$ जो हानि फंक्शन को कम करता रहता हैं
 * $$J = b \left( \mathbf{x}(t_{1}), t_{1} \right) + \int_{t_{0}}^{t_{1}} f \left( \mathbf{x}(t), \mathbf{u}(t), t \right) \mathrm{d} t$$
 * इस समस्या का समाधान इष्टतम नियंत्रण नियम या नीति के लिए सहयोगी होता है, $$\mathbf{u}^{\ast} = h(\mathbf{x}(t), t)$$, समीकरण के द्वारा इष्टतम प्रक्षेपवक्र $$\mathbf{x}^{\ast}$$ को उत्पन्न किया जाता है और $$J^{\ast}$$ कॉस्ट-टू-गो फ़ंक्शन के उत्तरार्द्ध को गतिक प्रोग्रामिंग के मौलिक समीकरण का पालन करके उक्त समीकरण द्वारा प्राप्त किया जाता हैं:
 * $$- J_{t}^{\ast} = \min_{\mathbf{u}} \left\{ f \left( \mathbf{x}(t), \mathbf{u}(t), t \right) + J_{x}^{\ast \mathsf{T}} \mathbf{g} \left( \mathbf{x}(t), \mathbf{u}(t), t \right) \right\}$$

हैमिल्टन-जैकोबी-बेलमैन समीकरण के रूप में जाना जाने वाला आंशिक अंतर समीकरण, जिसमें $$J_{x}^{\ast} = \frac{\partial J^{\ast}}{\partial \mathbf{x}} = \left[ \frac{\partial J^{\ast}}{\partial x_{1}} ~ \frac{\partial J^{\ast}}{\partial x_{2}} ~ \dots ~ \frac{\partial J^{\ast}}{\partial x_{n}} \right]^{\mathsf{T}}$$ और $$J_{t}^{\ast} = \frac{\partial J^{\ast}}{\partial t}$$. पाता है कि कम करना $$\mathbf{u}$$ के अनुसार $$t$$, $$\mathbf{x}$$, और अज्ञात फ़ंक्शन $$J_{x}^{\ast}$$ और फिर परिणाम को हैमिल्टन-जैकोबी-बेलमैन समीकरण में स्थानापन्न करता है जिससे कि आंशिक अंतर समीकरण को सीमा शर्त के साथ $$J \left( t_{1} \right) = b \left( \mathbf{x}(t_{1}), t_{1} \right)$$ से प्राप्त मान को उपयोग किया जा सके, व्यवहारिक रूप से, सही अनुकूलन संबंध के लिए कुछ असतत सन्निकटन के लिए सामान्यतः संख्यात्मक आंशिक अंतर समीकरणों की आवश्यकता होती है।

वैकल्पिक रूप से, निरंतर प्रक्रिया को असतत प्रणाली द्वारा अनुमानित किया जाता हैं, जो हैमिल्टन-जैकोबी-बेलमैन समीकरण के अनुरूप निम्नलिखित पुनरावृत्ति संबंध की ओर जाता है:
 * $$J_{k}^{\ast} \left( \mathbf{x}_{n-k} \right) = \min_{\mathbf{u}_{n-k}} \left\{ \hat{f} \left( \mathbf{x}_{n-k}, \mathbf{u}_{n-k} \right) + J_{k-1}^{\ast} \left( \hat{\mathbf{g}} \left( \mathbf{x}_{n-k}, \mathbf{u}_{n-k} \right) \right) \right\}$$

इस प्रकार $$k$$-वाँ चरण $$n$$ समान दूरी पर असतत समय अंतराल के लिए $$\hat{f}$$ और $$\hat{\mathbf{g}}$$ असतत सन्निकटन को $$f$$ और $$\mathbf{g}$$ द्वारा निरूपित करता हैं, इस कार्यात्मक समीकरण को बेलमैन समीकरण के रूप में जाना जाता है, जिसे अनुकूलन समीकरण के असतत सन्निकटन के सही समाधान के लिए हल किया जाता है।

अर्थशास्त्र से उदाहरण: रैमसे की इष्टतम बचत की समस्या
अर्थशास्त्र में, उद्देश्य सामान्यतः कुछ गतिक सामाजिक कल्याण कार्य को अधिकतम (न्यूनतम करने के अतिरिक्त) करना है। रैमसे की समस्या में, यह फलन उपभोग की मात्रा को उपयोगिता के स्तरों से संबंधित करता है। ढीले ढंग से बोलते हुए, इस प्रकार समसामयिक खपत और भविष्य की खपत (उत्पादन में उपयोग की जाने वाली भौतिक पूंजी में निवेश के माध्यम से) के बीच व्यापार-बंद का सामना करता है, जिसे अंतरकालिक मान के रूप में जाना जाता है। भविष्य की खपत को स्थिर दर $$\beta \in (0,1)$$ पर छूट दी जाती है, इस प्रकार पूंजी के संक्रमण समीकरण के लिए असतत सन्निकटन द्वारा दिया गया है
 * $$k_{t+1} = \hat{g} \left( k_{t}, c_{t} \right) = f(k_{t}) - c_{t}$$

जहाँ $$c$$ खपत है, $$k$$ पूंजी है, और $$f$$ इनडा स्थितियों को संतुष्ट करने वाला उत्पादन फलन है। प्रारंभिक पूंजी के स्टॉक $$k_{0} > 0$$ को इस प्रकार अवलेखित किया जा सकता है।

$$c_t$$ की अवधि में खपत के लिए $t$, और उपभोक्ता से उपयोगिता $$u(c_t)=\ln(c_t)$$ प्राप्त होती है, और यह जब तक उपभोक्ता रहता है तब तक प्राप्त होती हैं। मान लें कि उपभोक्ता अधीर है, इसलिए वह भविष्य की उपयोगिता को कारक $b$ द्वारा छूट देता है,  प्रत्येक अवधि पर जहां $$00$$ है, तथा यहाँ पर मान लीजिए कि इस अवधि की पूंजी और खपत अगली अवधि की पूंजी $$k_{t+1}=Ak^a_t - c_t$$ के रूप में निर्धारित की जाती है , जहाँ $A$ धनात्मक स्थिरांक $$0<a<1$$ है,और मान लें कि पूंजी ऋणात्मक नहीं हो सकती तब इस स्थिति में उपभोक्ता की निर्णय समस्या को इस प्रकार लिखा जा सकता है:


 * $$\max \sum_{t=0}^T b^t \ln(c_t)$$ का विषय है $$k_{t+1}=Ak^a_t - c_t \geq 0$$ सभी के लिए $$t=0,1,2,\ldots,T$$

इस तरह से लिखा गया, समस्या जटिल दिखती है, क्योंकि इसमें सभी विकल्प चरों को हल करने के लिए $$c_0, c_1, c_2, \ldots, c_T$$ उक्त समीकरण दिया गया है, ($$k_0$$ विकल्प चर नहीं है - उपभोक्ता की प्रारंभिक पूंजी दी गई है।)

इस समस्या को हल करने के लिए गतिक प्रोग्रामिंग दृष्टिकोण में इसे छोटे निर्णयों के अनुक्रम में तोड़ना सम्मलित है। ऐसा करने के लिए, हम मूल्य कार्यों के अनुक्रम को परिभाषित करते हैं, $$V_t(k)$$ के लिए $$t=0,1,2,\ldots,T,T+1$$ जो पूंजी की किसी भी राशि के होने के मूल्य का प्रतिनिधित्व करते हैं, तथा $k$  के लिए समय $t$  के बाद पूंजी होने से $$V_{T+1}(k)=0$$ (धारणा के अनुसार) कोई उपयोगिता नहीं है।

किसी भी समय पूंजी की किसी भी मात्रा के मूल्य की गणना बेलमैन समीकरण का उपयोग करके पीछे की ओर प्रेरण द्वारा की जा सकती है। इस समस्या में प्रत्येक के लिए $$t=0,1,2,\ldots,T$$, बेलमैन समीकरण है


 * $$V_t(k_t) \, = \, \max \left( \ln(c_t) + b V_{t+1}(k_{t+1}) \right)$$ का विषय है $$k_{t+1}=Ak^a_t - c_t \geq 0$$

यह समस्या हमारे द्वारा पहले लिखी गई समस्या से कहीं अधिक सरल है, क्योंकि इसमें केवल दो निर्णय चर सम्मलित हैं, $$c_t$$ और $$k_{t+1}$$. सहज रूप से, जन्म के समय अपनी संपूर्ण जीवन भर की योजना चुनने के अतिरिक्त, उपभोक्ता बार में कदम उठा सकता है। समय $t$ पर उनकी वर्तमान $$k_t$$ का मान दिया जाता है, और उसे केवल वर्तमान खपत $$c_t$$ और बचत $$k_{t+1}$$ को चुनने की आवश्यकता होती है।

वास्तव में इस समस्या को हल करने के लिए हम पीछे की ओर कार्य करते हैं। सरलता के लिए, पूँजी के वर्तमान स्तर को $k$. $$V_{T+1}(k)$$ रूप में निरूपित किया जाता है, जो पहले से ही ज्ञात होता है, इसलिए बेलमैन समीकरण का उपयोग करके हम $$V_T(k)$$ की गणना कर सकते हैं, और $$V_0(k)$$ के लिए इतने पर जब तक हम नहीं पहुंचते, जो पूरे जीवनकाल के लिए प्रारंभिक निर्णय समस्या का मान है। दूसरे शब्दों में हम $$V_{T-j+1}(k)$$ का मान प्राप्त कर लेते हैं, इस प्रकार हम $$V_{T-j}(k)$$ की गणना कर सकते हैं, जो कि अधिकतम है $$\ln(c_{T-j}) + b V_{T-j+1}(Ak^a-c_{T-j})$$, जहाँ $$c_{T-j}$$ चर है और $$Ak^a-c_{T-j} \ge 0$$ के द्वारा कार्य करता हैं, यह दिखाया जा सकता है कि $$t=T-j$$ का मान समय पर निर्भर करता है।


 * $$V_{T-j}(k) \, = \, a \sum_{i=0}^j a^ib^i \ln k + v_{T-j}$$

जहां प्रत्येक $$v_{T-j}$$ का मान स्थिर रहता है, और समय पर उपभोग करने के लिए इष्टतम मान $$t=T-j$$ है


 * $$c_{T-j}(k) \, = \, \frac{1}{\sum_{i=0}^j a^ib^i} Ak^a$$

जिसे सरल बनाया जा सकता है


 * $$\begin{align}

c_{T}(k) & = Ak^a\\ c_{T-1}(k) & = \frac{Ak^a}{1+ab}\\ c_{T-2}(k) & = \frac{Ak^a}{1+ab+a^2b^2}\\ &\dots\\ c_2(k) & = \frac{Ak^a}{1+ab+a^2b^2+\ldots+a^{T-2}b^{T-2}}\\ c_1(k) & = \frac{Ak^a}{1+ab+a^2b^2+\ldots+a^{T-2}b^{T-2}+a^{T-1}b^{T-1}}\\ c_0(k) & = \frac{Ak^a}{1+ab+a^2b^2+\ldots+a^{T-2}b^{T-2}+a^{T-1}b^{T-1}+a^Tb^T} \end{align}$$ हम देखते हैं कि वर्तमान धन के बड़े हिस्से का उपभोग करना इष्टतम है क्योंकि वृद्ध हो जाता है, अंत में शेष सभी धन का उपभोग अवधि में होता है $T$, जीवन की अंतिम अवधि।

कंप्यूटर प्रोग्रामिंग
डायनेमिक प्रोग्रामिंग को लागू करने के लिए समस्या में दो प्रमुख विशेषताएँ होनी चाहिए: इष्टतम सबस्ट्रक्चर और अतिव्यापी उपसमस्यायाओवरलैपिंग सब-प्रोब्लम्स। यदि किसी समस्या को गैर-अतिव्यापी उप-समस्याओं के इष्टतम समाधानों के संयोजन से हल किया जा सकता है, तो रणनीति को विभाजित करें और जीतें एल्गोरिथम कहा जाता है। यही कारण है कि मर्ज़ सॉर्ट और जल्दी से सुलझाएं को डायनेमिक प्रोग्रामिंग समस्याओं के रूप में वर्गीकृत नहीं किया गया है।

इष्टतम उपसंरचना का अर्थ है कि किसी दी गई अनुकूलन समस्या का समाधान उसकी उप-समस्याओं के इष्टतम समाधानों के संयोजन से प्राप्त किया जा सकता है। इस तरह के इष्टतम अवसंरचनाओं को सामान्यतः पुनरावर्तन के माध्यम से वर्णित किया जाता है। उदाहरण के लिए, ग्राफ जी = (वी, ई) दिया गया है, सबसे छोटा पथ पी शीर्ष यू से शीर्ष वी तक इष्टतम उपसंरचना प्रदर्शित करता है: इस सबसे छोटे पथ पी पर किसी भी मध्यवर्ती शीर्ष डब्ल्यू को लें। यदि p वास्तव में सबसे छोटा पथ है, तो इसे उप-पथ p में विभाजित किया जा सकता है1यू से डब्ल्यू और पी2w से v तक ऐसे हैं कि, बदले में, ये वास्तव में संबंधित शीर्षों के बीच सबसे छोटा रास्ता हैं (एल्गोरिदम के परिचय में वर्णित सरल कट-एंड-पेस्ट तर्क द्वारा)। इसलिए, पुनरावर्ती विधियाँ से सबसे छोटा रास्ता खोजने के लिए आसानी से समाधान तैयार कर सकता है, जो कि बेलमैन-फोर्ड एल्गोरिथम या फ्लोयड-वॉर्शल एल्गोरिथम करता है।

अतिव्यापी उप-समस्याओं का अर्थ है कि उप-समस्याओं का स्थान छोटा होना चाहिए, अर्थात, समस्या को हल करने वाले किसी भी पुनरावर्ती एल्गोरिथ्म को नई उप-समस्याओं को उत्पन्न करने के अतिरिक्त समान उप-समस्याओं को बार-बार हल करना चाहिए। उदाहरण के लिए, फाइबोनैचि श्रृंखला उत्पन्न करने के लिए पुनरावर्ती सूत्रीकरण पर विचार करें: Fi = Fi&minus;1 + Fi&minus;2, बेस केस F के साथ F1= F2= 1 तथा फिर F43 = F42+ F41, और F42 = F41+ F40 अब F41 दोनों F43 साथ ही F42 की पुनरावर्ती इसके उप मानों के लिए हल करके प्राप्त किया जाता है, यदि उप-समस्याओं की कुल संख्या वास्तव में छोटी है (उनमें से केवल 43), यदि हम इस तरह के सरल पुनरावर्ती समाधान को अपनाते हैं, तो हम उन्हीं समस्याओं को बार-बार हल करते हैं। डायनेमिक प्रोग्रामिंग इस तथ्य को ध्यान में रखता है और प्रत्येक उप-समस्या को केवल बार हल करता है।

इसे दो विधियों से प्राप्त किया जा सकता है:
 * टॉप-डाउन और बॉटम-अप डिज़ाइन या टॉप-डाउन दृष्टिकोण: यह किसी भी समस्या के पुनरावर्ती सूत्रीकरण का प्रत्यक्ष पतन है। यदि किसी समस्या का समाधान उसकी उप-समस्याओं के समाधान का उपयोग करके पुनरावर्ती रूप से तैयार किया जाता है, और यदि उसकी उप-समस्याएं अतिव्याप्त हैं, तो सूची में उप-समस्याओं के समाधानों को आसानी से याद या संग्रहीत किया जा सकता है। जब भी हम नई उप-समस्या को हल करने का प्रयास करते हैं, तो हम पहले यह देखने के लिए सूची की जांच करते हैं कि क्या यह पहले से ही हल हो गई है। यदि कोई समाधान अंकित किया गया है, तो हम इसका सीधे उपयोग कर सकते हैं, अन्यथा हम उप-समस्या को हल करते हैं और सूची में उसका समाधान जोड़ते हैं।
 * टॉप-डाउन और बॉटम-अप डिज़ाइन या बॉटम-अप दृष्टिकोण: बार जब हम किसी समस्या के समाधान को उसकी उप-समस्याओं के संदर्भ में पुनरावर्ती रूप से तैयार कर लेते हैं, तो हम समस्या को नीचे-ऊपर फैशन में सुधारने का प्रयास कर सकते हैं: उप को हल करने का प्रयास करें -समस्याएं पहले और उनके समाधान का निर्माण करने के लिए उपयोग करें और बड़ी उप-समस्याओं के समाधान पर पहुंचें। यह भी सामान्यतः छोटी उप-समस्याओं के समाधान का उपयोग करके बड़ी और बड़ी उप-समस्याओं के समाधान उत्पन्न करके सारणीबद्ध रूप में किया जाता है। उदाहरण के लिए, यदि हम पहले से ही F41 और F40 का मान जानते हैं, हम सीधे F42 के मान की गणना कर सकते हैं।

कॉल-बाय-नाम मूल्यांकन (इस तंत्र को कॉल-बाय-ज़रूरत के रूप में जाना जाता है) को गति देने के लिए, कुछ प्रोग्रामिंग लैंग्वेज स्वचालित रूप से तर्कों के विशेष सेट के साथ फ़ंक्शन कॉल के परिणाम को याद कर सकती हैं। कुछ भाषाएँ इसे पोर्टेबल रूप से संभव बनाती हैं (जैसे स्कीम (प्रोग्रामिंग लैंग्वेज), सामान्य लिस्प, पर्ल या डी (प्रोग्रामिंग भाषा))। कुछ भाषाओं में स्वचालित संस्मरण होता है जिसके लिए बिल्ट इन, जैसे कि टेबल्ड प्रोलॉग और j (प्रोग्रामिंग लैंग्वेज), जो m के लिए विशेषण करने के साथ संस्मरण का समर्थन करता है। किसी भी स्थिति में, यह केवल संदर्भित पारदर्शी कार्य करने के लिए ही संभव है। शब्द-पुनर्लेखन आधारित भाषाओं जैसे वोल्फ्राम भाषा के भीतर मेमोइज़ेशन को आसानी से सुलभ डिज़ाइन पैटर्न के रूप में भी देखा जाता है।

जैव सूचना विज्ञान
अनुक्रम संरेखण, प्रोटीन तह, आरएनए संरचना भविष्यवाणी और प्रोटीन-डीएनए बंधन जैसे कार्यों के लिए जैव सूचना विज्ञान में गतिक प्रोग्रामिंग का व्यापक रूप से उपयोग किया जाता है। प्रोटीन-डीएनए बाइंडिंग के लिए पहला गतिक प्रोग्रामिंग एल्गोरिदम 1970 के दशक में संयुक्त राज्य अमेरिका में चार्ल्स डेलीसी द्वारा तथा यूएसएसआर में जॉर्जी गुरस्की और अलेक्जेंडर ज़सेदातेलेव द्वारा स्वतंत्र रूप से विकसित किया गया था। हाल ही में ये एल्गोरिदम जैव सूचना विज्ञान और कम्प्यूटेशनल बायोलॉजी विज्ञान विशेष रूप से न्यूक्लियोसोम पोजिशनिंग और प्रतिलेखन कारक बाइंडिंग के अध्ययन में बहुत लोकप्रिय हो गए हैं।

सबसे छोटी पथ समस्या के लिए दिज्क्स्ट्रा का एल्गोरिथ्म
एक गतिक प्रोग्रामिंग दृष्टिकोण से, सबसे छोटी पथ समस्या के लिए दिज्क्स्ट्रा का एल्गोरिथ्म क्रमिक सन्निकटन योजना है जो रीचिंग विधि द्वारा सबसे छोटी पथ समस्या के लिए गतिक प्रोग्रामिंग कार्यात्मक समीकरण को हल करती है।

वास्तव में, एल्गोरिथम के पीछे के तर्क की डिजस्ट्रा की व्याख्या, अर्थात् "Problem 2. Find the path of minimum total length between two given nodes $P$ and $Q$.

We use the fact that, if $R$ is a node on the minimal path from $P$ to $Q$, knowledge of the latter implies the knowledge of the minimal path from $P$ to $R$."

सबसे छोटी पथ समस्या के संदर्भ में रिचर्ड बेलमैन|बेलमैन के अनुकूलता के प्रसिद्ध सिद्धांत की व्याख्या है।

फाइबोनैचि अनुक्रम
फाइबोनैचि अनुक्रम के nवें सदस्य की गणना में गतिशील प्रोग्रामिंग का उपयोग करने से इसके प्रदर्शन में काफी सुधार होता है। यहाँ गणितीय परिभाषा पर सीधे आधारित एक भोली कार्यान्वयन है:

'फ़ंक्शन' फाइब (एन) 'अगर' एन <= 1 'वापसी' एन 'रिटर्न' फाइब (एन − 1) + फाइब (एन − 2)

ध्यान दें कि अगर हम फोन करते हैं, कहते हैं,, हम एक कॉल ट्री बनाते हैं जो फ़ंक्शन को एक ही मान पर कई अलग-अलग बार कॉल करता है:

विशेष रूप से,  स्क्रैच से तीन बार गणना की गई थी। बड़े उदाहरणों में, के कई और मान , या उप-समस्याओं की पुनर्गणना की जाती है, जिससे एक चरघातांकी समय एल्गोरिद्म तैयार होता है।

अब, मान लीजिए कि हमारे पास एक साधारण साहचर्य सरणी वस्तु है, m, जो प्रत्येक मान को मैप करता है  इसके परिणाम के लिए पहले से ही इसकी गणना की जा चुकी है, और हम इसका उपयोग करने और इसे अपडेट करने के लिए अपने कार्य को संशोधित करते हैं। परिणामी फ़ंक्शन को घातीय समय के बजाय केवल बिग-ओ नोटेशन (एन) समय की आवश्यकता होती है (लेकिन बिग-ओ नोटेशन (एन) स्पेस की आवश्यकता होती है):

'var' m := 'map'(0 → 0, 1 → 1) 'फ़ंक्शन' फाइब (एन) 'अगर कुंजी' एन 'मानचित्र में नहीं है' एम एम [एन]: = फाइब (एन - 1) + फाइब (एन - 2) 'वापसी' एम [एन]

मूल्यों को सहेजने की यह तकनीक जिसकी गणना पहले ही की जा चुकी है, मेमोइज़ेशन कहलाती है; यह टॉप-डाउन दृष्टिकोण है, क्योंकि हम पहले समस्या को उप-समस्याओं में तोड़ते हैं और फिर मूल्यों की गणना और संग्रह करते हैं।

बॉटम-अप दृष्टिकोण में, हम के छोटे मानों की गणना करते हैं  पहले, फिर उनसे बड़े मूल्य बनाएँ। यह विधि O(n) समय का भी उपयोग करती है क्योंकि इसमें एक लूप होता है जो n - 1 बार दोहराता है, लेकिन यह केवल स्थिर (O(1)) स्थान लेता है, शीर्ष-डाउन दृष्टिकोण के विपरीत जिसके लिए O(n) स्थान की आवश्यकता होती है नक्शा स्टोर करें।

'फ़ंक्शन' फाइब (एन) 'अगर' एन = 0 'वापसी' 0 'अन्य' 'var' पिछला फ़िब: = 0, करंट फ़िब: = 1 'दोहराना' n − 1 'बार' // n = 1 होने पर लूप को छोड़ दिया जाता है 'var' newFib := पिछलाFib + currentFib पिछलाफाइब := करेंटफाइब करेंटफाइब := newFib 'वापसी' करेंटFib

दोनों उदाहरणों में, हम केवल गणना करते हैं  एक बार, और फिर दोनों की गणना करने के लिए इसका उपयोग करें   और , इसकी गणना करने के बजाय हर बार उनमें से किसी एक का मूल्यांकन किया जाता है।

एक प्रकार का संतुलित 0–1 मैट्रिक्स
किसी की स्थिति के लिए, या तो शून्य या एक मान निर्दिष्ट करने की समस्या पर विचार करें $n &times; n$ मैट्रिक्स, के साथ $n$ यहां तक ​​कि, ताकि प्रत्येक पंक्ति और प्रत्येक कॉलम में बिल्कुल शामिल हो $n / 2$ शून्य और $n / 2$ वाले। हम पूछते हैं कि दिए गए के लिए कितने अलग-अलग कार्य हैं $$n$$. उदाहरण के लिए, कब $n = 4$, पांच संभावित समाधान हैं


 * $$\begin{bmatrix}

0 & 1 & 0 & 1 \\ 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 \\ 1 & 0 & 1 & 0 \end{bmatrix} \text{ and } \begin{bmatrix} 0 & 0 & 1 & 1 \\ 0 & 0 & 1 & 1 \\ 1 & 1 & 0 & 0 \\ 1 & 1 & 0 & 0 \end{bmatrix} \text{ and } \begin{bmatrix} 1 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 \\ 1 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 \end{bmatrix} \text{ and } \begin{bmatrix} 1 & 0 & 0 & 1 \\ 0 & 1 & 1 & 0 \\ 0 & 1 & 1 & 0 \\ 1 & 0 & 0 & 1 \end{bmatrix} \text{ and } \begin{bmatrix} 1 & 1 & 0 & 0 \\ 1 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 1 & 1 \end{bmatrix}.$$ कम से कम तीन संभावित दृष्टिकोण हैं: क्रूर-बल खोज, बैक ट्रैकिंग और डायनेमिक प्रोग्रामिंग।

क्रूर बल में शून्य और एक के सभी असाइनमेंट की जाँच करना और संतुलित पंक्तियों और स्तंभों की गणना करना शामिल है ($n / 2$ शून्य और $n / 2$ वाले)। जैसे वहां है $$2^{n^2}$$ संभावित कार्य और $$\tbinom{n}{n/2}^n$$ समझदार असाइनमेंट, यह रणनीति व्यावहारिक नहीं है सिवाय शायद तक $$n=6$$.

इस समस्या के लिए बैकट्रैकिंग में मैट्रिक्स तत्वों के कुछ क्रम को चुनना और पुनरावर्ती रूप से एक या शून्य को रखना शामिल है, जबकि यह जांचते हुए कि प्रत्येक पंक्ति और कॉलम में तत्वों की संख्या जिन्हें निर्दिष्ट नहीं किया गया है, साथ ही एक या शून्य की संख्या दोनों कम से कम हैं $n / 2$. क्रूर बल की तुलना में अधिक परिष्कृत होने के बावजूद, यह दृष्टिकोण हर समाधान पर एक बार जाएगा, जिससे यह अव्यवहारिक हो जाएगा $n$ छह से बड़ा, चूंकि समाधान की संख्या पहले से ही 116,963,796,250 है $n$= 8, जैसा कि हम देखेंगे।

डायनेमिक प्रोग्रामिंग उन सभी का दौरा किए बिना समाधानों की संख्या की गणना करना संभव बनाता है। पहली पंक्ति के लिए बैकट्रैकिंग मानों की कल्पना करें - प्रत्येक पहली पंक्ति मान के लिए प्राप्त समाधानों की सटीक गणना करने में सक्षम होने के लिए हमें शेष पंक्तियों के बारे में क्या जानकारी चाहिए? हमें विचार विमर्श करना है $k &times; n$ बोर्ड, कहाँ $1 &le; k &le; n$, किसका $$k$$ पंक्तियाँ होती हैं $$n/2$$ शून्य और $$n/2$$ वाले। फ़ंक्शन f जिस पर मेमोइज़ेशन लागू किया गया है, पूर्णांकों के n जोड़े के वैक्टर को स्वीकार्य बोर्डों (समाधान) की संख्या में मैप करता है। प्रत्येक कॉलम के लिए एक जोड़ी है, और इसके दो घटक क्रमशः शून्य की संख्या और उस कॉलम में अभी तक रखे जाने वाले लोगों को इंगित करते हैं। हम का मूल्य खोजते हैं $$ f((n/2, n/2), (n/2, n/2), \ldots (n/2, n/2)) $$ ($$n$$ तर्क या एक वेक्टर $$n$$ तत्व)। उप-समस्याओं के निर्माण की प्रक्रिया में प्रत्येक पर पुनरावृति शामिल है $$\tbinom{n}{n/2}$$ बोर्ड की शीर्ष पंक्ति के लिए संभावित असाइनमेंट, और प्रत्येक कॉलम के माध्यम से जाना, उस कॉलम के जोड़े के उपयुक्त तत्व से एक घटाना, इस पर निर्भर करता है कि शीर्ष पंक्ति के असाइनमेंट में शून्य है या उस स्थिति में एक है। यदि कोई एक परिणाम नकारात्मक है, तो असाइनमेंट अमान्य है और समाधान के सेट में योगदान नहीं करता है (पुनरावर्तन बंद हो जाता है)। अन्यथा, हमारे पास शीर्ष पंक्ति के लिए एक असाइनमेंट है $k &times; n$ बोर्ड और पुनरावर्ती रूप से शेष के समाधान की संख्या की गणना करें $( k &minus; 1) &times; n$ बोर्ड, शीर्ष पंक्ति के प्रत्येक स्वीकार्य असाइनमेंट के लिए समाधान की संख्या जोड़ना और योग वापस करना, जिसे याद किया जा रहा है। आधार मामला तुच्छ उपसमस्या है, जो a के लिए होता है $1 &times; n$ तख़्ता। इस बोर्ड के समाधान की संख्या या तो शून्य या एक है, यह इस बात पर निर्भर करता है कि सदिश किसका क्रमचय है $n / 2$ $$(0, 1)$$ और $n / 2$ $$(1, 0)$$ जोड़े हैं या नहीं।

उदाहरण के लिए ऊपर दिखाए गए पहले दो बोर्डों में सदिशों का क्रम होगा  ((2, 2) (2, 2) (2, 2) (2, 2)) ((2, 2) (2, 2) (2, 2) (2, 2)) के = 4 0 1 0 1 0 0 1 1

((1, 2) (2, 1) (1, 2) (2, 1)) ((1, 2) (1, 2) (2, 1) (2, 1)) के = 3 1 0 1 0 0 0 1 1

((1, 1) (1, 1) (1, 1) (1, 1)) ((0, 2) (0, 2) (2, 0) (2, 0)) के = 2 0 1 0 1 1 1 0 0

((0, 1) (1, 0) (0, 1) (1, 0)) ((0, 1) (0, 1) (1, 0) (1, 0)) k = 1 1 0 1 0 1 1 0 0

((0, 0) (0, 0) (0, 0) (0, 0)) ((0, 0) (0, 0), (0, 0) (0, 0)) 

समाधान की संख्या है


 * $$ 1,\, 2,\, 90,\, 297200,\, 116963796250,\, 6736218287430460752, \ldots $$

गतिशील प्रोग्रामिंग दृष्टिकोण के मैपल कार्यान्वयन के लिंक #बाहरी लिंक के बीच मिल सकते हैं।

चेकरबोर्ड
n × n वर्गों और एक लागत समारोह के साथ एक बिसात पर विचार करें  जो वर्ग से जुड़ी लागत लौटाता है   (  पंक्ति होने के नाते,   स्तंभ होना)। उदाहरण के लिए (5 × 5 बिसात पर),

इस प्रकार मान लें कि एक चेकर था जो पहली रैंक (यानी, पंक्ति) पर किसी भी वर्ग से शुरू हो सकता था और आप अंतिम रैंक तक पहुंचने के लिए सबसे छोटा रास्ता (प्रत्येक विज़िट की गई रैंक पर न्यूनतम लागत का योग) जानना चाहते थे; यह मानते हुए कि चेकर केवल तिरछे बाएँ आगे, तिरछे दाएँ आगे या सीधे आगे बढ़ सकता है। यानी चेकर ऑन  में जा सकते हैं ,   या. यह समस्या इष्टतम सबस्ट्रक्चर प्रदर्शित करती है। अर्थात्, संपूर्ण समस्या का समाधान उप-समस्याओं के समाधान पर निर्भर करता है। आइए एक फ़ंक्शन को परिभाषित करें  जैसा


 * q(i, j) = वर्ग (i, j) तक पहुँचने के लिए न्यूनतम लागत।

रैंक से शुरू  और रैंक पर उतरना , हम प्रत्येक क्रमिक रैंक पर सभी वर्गों के लिए इस फ़ंक्शन के मान की गणना करते हैं। प्रत्येक रैंक पर न्यूनतम मान रखने वाले वर्ग को चुनना हमें रैंक के बीच सबसे छोटा रास्ता देता है   और रैंक.

कार्यक्रम  इसके नीचे के तीन वर्गों में से किसी एक तक पहुंचने के लिए न्यूनतम लागत के बराबर है (चूंकि केवल वही वर्ग हैं जो इस तक पहुंच सकते हैं) प्लस. उदाहरण के लिए:


 * $$q(A) = \min(q(B),q(C),q(D))+c(A) \, $$

अब, परिभाषित करते हैं  कुछ अधिक सामान्य शब्दों में:


 * $$q(i,j)=\begin{cases} \infty & j < 1 \text{ or }j > n \\ c(i, j) & i = 1 \\ \min(q(i-1, j-1), q(i-1, j), q(i-1, j+1)) + c(i,j) & \text{otherwise.}\end{cases}$$

इस समीकरण की पहली पंक्ति एक बोर्ड से संबंधित है जिसे वर्गों के रूप में अनुक्रमित किया गया है  सबसे कम सीमा पर और   उच्चतम सीमा पर। दूसरी पंक्ति निर्दिष्ट करती है कि पहली रैंक पर क्या होता है; एक आधार मामला प्रदान करना। तीसरी पंक्ति, प्रत्यावर्तन, महत्वपूर्ण हिस्सा है। यह प्रतिनिधित्व करता है   उदाहरण में शर्तें। इस परिभाषा से हम सीधा पुनरावर्ती कोड प्राप्त कर सकते हैं. निम्नलिखित स्यूडोकोड में,  बोर्ड का आकार है,   लागत समारोह है, और   कम से कम कई मान लौटाता है:

फ़ंक्शन minCost(i, j)    यदि जे <1 या जे> एन वापसी अनंत और अगर मैं = 1 वापसी सी (मैं, जे) अन्य वापसी मिनट (minCost(i-1, j-1), minCost(i-1, j), minCost(i-1, j+1) ) + c(i, j)

यह फ़ंक्शन केवल पथ लागत की गणना करता है, वास्तविक पथ की नहीं। हम नीचे वास्तविक पथ पर चर्चा करते हैं। यह, फाइबोनैचि-संख्या उदाहरण की तरह, बहुत धीमा है क्योंकि यह अतिव्यापी उप-समस्या विशेषता को भी प्रदर्शित करता है। यही है, यह एक ही पथ लागत को बार-बार पुनर्गणना करता है। हालाँकि, यदि हम दो-आयामी सरणी में पथ लागतों को संग्रहीत करते हैं, तो हम इसे नीचे-ऊपर फैशन में बहुत तेज़ी से गणना कर सकते हैं  फ़ंक्शन का उपयोग करने के बजाय। यह पुनर्गणना से बचा जाता है; सरणी के लिए आवश्यक सभी मान   समय से पहले केवल एक बार गणना की जाती है। के लिए पूर्व-गणना मान   जरूरत पड़ने पर बस ऊपर देखा जाता है।

हमें यह भी जानने की जरूरत है कि वास्तविक सबसे छोटा रास्ता क्या है। ऐसा करने के लिए, हम एक और सरणी का उपयोग करते हैं ; एक पूर्ववर्ती सरणी। यह सरणी किसी भी वर्ग का पथ रिकॉर्ड करती है. के पूर्ववर्ती  इंडेक्स के सापेक्ष ऑफ़सेट के रूप में मॉडलिंग किया गया है (में  ) की पूर्व-गणना पथ लागत की. पूर्ण पथ का पुनर्निर्माण करने के लिए, हम इसके पूर्ववर्ती को देखते हैं, फिर उस वर्ग का पूर्ववर्ती, फिर उस वर्ग का पूर्ववर्ती, और इसी तरह पुनरावर्ती रूप से, जब तक कि हम प्रारंभिक वर्ग तक नहीं पहुंच जाते। निम्नलिखित स्यूडोकोड पर विचार करें:

फ़ंक्शन कंप्यूटशॉर्टेस्टपाथएरेज़ x के लिए 1 से n तक क्यू [1, एक्स] := सी (1, एक्स) वाई के लिए 1 से एन तक क्ष[य, 0] := अनंत क्यू [वाई, एन + 1] : = अनंत वाई के लिए 2 से एन तक x के लिए 1 से n तक एम : = मिनट (क्यू [वाई -1, एक्स -1], क्यू [वाई -1, एक्स], क्यू [वाई -1, एक्स + 1]) क्यू [वाई, एक्स]: = एम + सी (वाई, एक्स) अगर एम = क्यू [वाई -1, एक्स -1] पी [वाई, एक्स]: = -1 और अगर एम = क्यू [वाई -1, एक्स] पी [वाई, एक्स] : = 0 अन्य पी [वाई, एक्स] : = 1

अब शेष न्यूनतम खोजने और इसे प्रिंट करने का एक साधारण मामला है।

फ़ंक्शन गणना सबसे छोटा पथ कंप्यूटशॉर्टेस्टपाथअरे मिनइंडेक्स: = 1 मिनट := क्ष[एन, 1] मैं 2 से एन के लिए अगर क्यू [एन, मैं] <मिनट मिनइंडेक्स: = मैं मिनट : = क्यू [एन, मैं] प्रिंटपाथ (एन, मिनइंडेक्स)

फ़ंक्शन प्रिंटपाथ (वाई, एक्स) प्रिंट (एक्स) प्रिंट (<-) अगर वाई = 2 प्रिंट (एक्स + पी [वाई, एक्स]) अन्य प्रिंटपाथ (वाई -1, एक्स + पी [वाई, एक्स])

अनुक्रम संरेखण
आनुवंशिकी में, अनुक्रम संरेखण एक महत्वपूर्ण अनुप्रयोग है जहां गतिशील प्रोग्रामिंग आवश्यक है। आमतौर पर, समस्या में एक तत्व को बदलने, डालने या हटाने वाले संपादन कार्यों का उपयोग करके एक अनुक्रम को दूसरे में बदलना शामिल है। प्रत्येक ऑपरेशन की एक संबद्ध लागत होती है, और लक्ष्य संपादन दूरी का पता लगाना है।

समस्या को स्वाभाविक रूप से एक पुनरावर्तन के रूप में कहा जा सकता है, एक अनुक्रम A को अनुक्रम B में या तो बेहतर रूप से संपादित किया जाता है:


 * 1) बी के पहले अक्षर को सम्मिलित करना, और ए और बी की पूंछ का एक इष्टतम संरेखण करना
 * 2) ए के पहले अक्षर को हटाना, और ए और बी की पूंछ का इष्टतम संरेखण करना
 * 3) A के पहले अक्षर को B के पहले अक्षर से बदलना, और A और B की पूंछ के इष्टतम संरेखण का प्रदर्शन करना।

आंशिक संरेखण को एक मैट्रिक्स में सारणीबद्ध किया जा सकता है, जहां सेल (i,j) में A[1..i] से B[1..j] के इष्टतम संरेखण की लागत शामिल है। सेल (i, j) में लागत की गणना संबंधित संचालन की लागत को उसके पड़ोसी सेल की लागत में जोड़कर और इष्टतम का चयन करके की जा सकती है।

विभिन्न संस्करण मौजूद हैं, स्मिथ-वाटरमैन एल्गोरिथम और नीडलमैन-वुन्श एल्गोरिथम देखें।

हनोई पहेली का टॉवर
हनोई की मीनार या हनोई की मीनारें एक गणितीय खेल या पहेली है। इसमें तीन छड़ें और विभिन्न आकारों की कई डिस्क होती हैं जो किसी भी छड़ पर स्लाइड कर सकती हैं। पहेली एक छड़ पर आकार के आरोही क्रम में एक साफ ढेर में डिस्क के साथ शुरू होती है, जो शीर्ष पर सबसे छोटी होती है, इस प्रकार एक शंक्वाकार आकार बनाती है।

पहेली का उद्देश्य निम्नलिखित नियमों का पालन करते हुए पूरे ढेर को दूसरी छड़ पर ले जाना है:


 * एक समय में केवल एक ही डिस्क को चलाया जा सकता है।
 * प्रत्येक चाल में एक रॉड से ऊपरी डिस्क को लेना और दूसरी रॉड पर स्लाइड करना शामिल है, जो उस रॉड पर पहले से मौजूद अन्य डिस्क के ऊपर हो सकती है।
 * छोटी डिस्क के ऊपर कोई डिस्क नहीं रखी जा सकती है।

गतिशील प्रोग्रामिंग समाधान में बेलमैन समीकरण को हल करना शामिल है


 * एस (एन, एच, टी) = एस (एन-1, एच, नहीं (एच, टी)); एस (1, एच, टी); एस(एन-1,नहीं(एच,टी),टी)

जहाँ n स्थानांतरित होने वाली डिस्क की संख्या को दर्शाता है, h होम रॉड को दर्शाता है, t लक्ष्य रॉड को दर्शाता है, not(h,t) तीसरी रॉड को दर्शाता है (न तो h और न ही t), ; संयोजन को दर्शाता है, और


 * S(n, h, t) := n डिस्क वाली समस्या का समाधान जिसे रॉड h से रॉड t में ले जाना है।

n = 1 के लिए समस्या तुच्छ है, अर्थात् S (1, h, t) = एक डिस्क को रॉड h से रॉड t तक ले जाएँ (केवल एक डिस्क शेष है)।

इस समाधान के लिए आवश्यक चालों की संख्या 2 हैn − 1। यदि उद्देश्य चालों की संख्या को 'अधिकतम' करना है (बिना साइकिल चलाए) तो गतिशील प्रोग्रामिंग बेलमैन समीकरण थोड़ा अधिक जटिल है और 3n − 1 चालें आवश्यक हैं।

अंडे छोड़ने वाली पहेली
N = 2 अंडे और H = 36 मंजिलों वाली इमारत से जुड़ी इस प्रसिद्ध पहेली के उदाहरण का विवरण निम्नलिखित है: : मान लीजिए कि हम जानना चाहते हैं कि 36 मंजिला इमारत में कौन सी मंजिल अंडे छोड़ने के लिए सुरक्षित है, और कौन से अंडे लैंडिंग पर टूट जाएंगे (यू.एस. अंग्रेजी शब्दावली का उपयोग करते हुए, जिसमें पहली मंजिल जमीनी स्तर पर है)। हम कुछ धारणाएँ बनाते हैं:


 * जो अंडा गिरकर बच जाता है उसे फिर से उपयोग किया जा सकता है।
 * टूटे हुए अंडे को फेंक देना चाहिए।
 * गिरने का प्रभाव सभी अंडों पर जैसा होता है।
 * यदि अंडा गिराने पर टूट जाता है तो ऊपर की खिड़की से गिराने पर टूट जाता है।
 * यदि अंडा गिरने से बच जाता है, तो वह कम गिरने से बचेगा।
 * इस बात से इंकार नहीं किया जाता है कि पहली मंजिल की खिड़कियां अंडे तोड़ती हैं, और न ही इस बात से इंकार किया जाता है कि अंडे 36 वीं मंजिल की खिड़कियों से बच सकते हैं।


 * यदि केवल अंडा उपलब्ध हो और हम सही परिणाम प्राप्त करना सुनिश्चित करना चाहते हैं, तो प्रयोग केवल ही विधियाँ से किया जा सकता है। पहली मंजिल की खिड़की से अंडा गिराओ; यदि यह बच जाता है, तो इसे दूसरी मंजिल की खिड़की से गिरा दें। इस तरह ऊपर की ओर से तब तक यह प्रक्रिया जारी रखते हैं जब तक कि यह टूट न जाए। सबसे खराब स्थिति में, इस विधि में 36 बूंदों की आवश्यकता हो सकती है। मान लीजिए 2 अंडे उपलब्ध हैं। अंडे की बूंदों की सबसे कम संख्या क्या है जो सभी मामलों में कार्य करने की गारंटी देती है?

इस पहेली के लिए गतिक प्रोग्रामिंग बेलमैन समीकरण प्राप्त करने के लिए, गतिक प्रोग्रामिंग मॉडल की स्थिति को जोड़ी s = (n, के) होने दें, जहां


 * n = उपलब्ध परीक्षण अंडों की संख्या, n = 0, 1, 2, 3, ..., N − 1।
 * k = (लगातार) मंजिलों की संख्या जिनका अभी परीक्षण किया जाना है, k = 0, 1, 2, ..., H − 1।

उदाहरण के लिए, s = (2,6) इंगित करता है कि दो परीक्षण अंडे उपलब्ध हैं और 6 (लगातार) मंजिलों का परीक्षण किया जाना बाकी है। प्रक्रिया की प्रारंभिक अवस्था s = (N,H) है जहाँ N प्रयोग के प्रारंभ में उपलब्ध परीक्षण अंडों की संख्या को दर्शाता है। यह प्रक्रिया या तो समाप्त हो जाती है या जब n = 0 होने पर या जब k = 0, जो भी पहले होता है तो इन्में से कोई और परीक्षण अंडे पर नहीं किया जाचा हैं। यदि समाप्ति स्थिति s = (0,k) और k > 0 पर होती है, तो परीक्षण विफल माना जाता हैं।


 * W(n,k) = सबसे खराब स्थिति के अनुसार महत्वपूर्ण मंजिल के मूल्य की पहचान करने के लिए आवश्यक परीक्षणों की न्यूनतम संख्या यह देखते हुए कि प्रक्रिया s' = (n,k) की स्थिति में है ' ।

तभी यह दिखाया जा सकता है


 * W(n,k) = 1 + min{max(W(n − 1, x − 1), W(n,k − x)): x = 1, 2, ..., k }

W(n,0) = 0 सभी n > 0 के लिए और W(1,k) = k सभी k के लिए। n और k के मानों को व्यवस्थित रूप से बढ़ाकर इस समीकरण को पुनरावृत्त रूप से हल करना आसान है।

एक अलग पैरामीट्रिजेशन का उपयोग करके तेज़ डीपी समाधान
ध्यान दें कि उपरोक्त समाधान लेता है $$O( n k^2 )$$ डीपी समाधान के साथ समय। इसमें सुधार किया जा सकता है $$O( n k \log k )$$ इष्टतम पर द्विआधारी खोज द्वारा समय $$x$$ उपरोक्त पुनरावृत्ति में, चूंकि $$W(n-1,x-1)$$ में बढ़ रहा है $$x$$ जबकि $$W(n,k-x)$$ में घट रहा है $$x$$, इस प्रकार एक स्थानीय न्यूनतम $$\max(W(n-1,x-1),W(n,k-x))$$ एक वैश्विक न्यूनतम है। इसके अलावा, इष्टतम भंडारण करके $$x$$ डीपी तालिका में प्रत्येक सेल के लिए और पिछले सेल के लिए इसके मान का जिक्र करते हुए, इष्टतम $$x$$ प्रत्येक कोशिका के लिए निरंतर समय में पाया जा सकता है, इसे सुधारने के लिए $$O( n k )$$ समय। हालाँकि, एक और भी तेज़ समाधान है जिसमें समस्या का एक अलग पैरामीट्रिजेशन शामिल है:

होने देना $$k$$ मंजिलों की कुल संख्या इस प्रकार हो कि अंडे नीचे गिरने पर टूट जाएं $$k$$वीं मंजिल (उपरोक्त उदाहरण लेने के बराबर है $$k=37$$).

होने देना $$m$$ वह न्यूनतम मंजिल हो जिससे अंडे को तोड़ने के लिए गिराया जाना चाहिए।

होने देना $$f(t,n)$$ के मूल्यों की अधिकतम संख्या हो $$m$$ जिनका उपयोग करके पहचाना जा सकता है $$t$$ कोशिश करता है और $$n$$ अंडे।

तब $$f(t,0) = f(0,n) = 1$$ सभी के लिए $$t,n \geq 0$$.

होने देना $$a$$ वह मंजिल हो जहां से इष्टतम रणनीति में पहला अंडा गिराया गया हो।

अगर पहला अंडा फूटा, $$m$$ से है $$1$$ को $$a$$ और अधिक से अधिक का उपयोग कर अलग पहचान $$t-1$$ कोशिश करता है और $$n-1$$ अंडे।

अगर पहला अंडा नहीं फूटा, $$m$$ से है $$a+1$$ को $$k$$ और अलग पहचान का उपयोग कर $$t-1$$ कोशिश करता है और $$n$$ अंडे।

इसलिए, $$f(t,n) = f(t-1,n-1) + f(t-1,n)$$.

फिर समस्या न्यूनतम खोजने के बराबर है $$x$$ ऐसा है कि $$f(x,n) \geq k$$.

ऐसा करने के लिए, हम गणना कर सकते हैं $$\{ f(t,i) : 0 \leq i \leq n \}$$ बढ़ाने के क्रम में $$t$$, जो लगेगा $$O( n x )$$ समय।

इस प्रकार, यदि हम अलग से के मामले को संभालते हैं $$n=1$$, एल्गोरिथम लगेगा $$O( n \sqrt{k} )$$ समय।

लेकिन पुनरावृत्ति संबंध वास्तव में हल करके हल किया जा सकता है $$f(t,n) = \sum_{i=0}^{n}{ \binom{t}{i} }$$, जिसकी गणना की जा सकती है $$O(n)$$ पहचान का उपयोग करते हुए समय $$\binom{t}{i+1} = \binom{t}{i} \frac{t-i}{i+1}$$ सभी के लिए $$i \geq 0$$.

तब से $$f(t,n) \leq f(t+1,n)$$ सभी के लिए $$t \geq 0$$, हम बाइनरी सर्च कर सकते हैं $$t$$ ढूँढ़ने के लिए $$x$$, एक दे रहा है $$O( n \log k )$$ कलन विधि।

आव्युह श्रृंखला गुणन
आव्युह श्रृंखला गुणन प्रसिद्ध उदाहरण है जो गतिक प्रोग्रामिंग की उपयोगिता को प्रदर्शित करता है। उदाहरण के लिए, इंजीनियरिंग अनुप्रयोगों को अधिकांशतः मेट्रिसेस की श्रृंखला को गुणा करना पड़ता है। बड़े आयामों के आव्यूहों को खोजना आश्चर्यजनक नहीं है, उदाहरण के लिए 100×100 इत्यादि। इसलिए, हमारा कार्य आव्युह $A_1, A_2, .... A_n$. को गुणा करना है, आव्युह गुणन विनिमेय नहीं है, किन्तु साहचर्य है; और हम समय में केवल दो आव्यूहों का ही गुणा कर सकते हैं। इसलिए, हम आव्युह की इस श्रृंखला को कई अलग-अलग विधियों से गुणा कर सकते हैं, उदाहरण के लिए:



और इसी प्रकार आव्युह की इस श्रृंखला को गुणा करने के कई विधियाँ हैं। वे सभी ही अंतिम परिणाम देंगे, चूंकि उन्हें गणना करने में अधिक या कम समय लगेगा, जिसके आधार पर विशेष आव्युह को गुणा किया जाता है। यदि आव्युह A का आयाम m×n है और आव्युह B का आयाम n×q है, तो आव्युह C=A×B का आयाम m×q होगा, और इसके लिए m*n*q स्केलर गुणन की आवश्यकता होगी (उद्देश्यों के लिए सरलीकृत आव्युह गुणन एल्गोरिथ्म का उपयोग करके) चित्रण में दिखाया गया हैं।

उदाहरण के लिए, आइए आव्यूहों A, B और C का गुणा करें। मान लें कि उनकी विमाएँ क्रमशः m×n, n×p और p×s हैं। आव्युह A×B×C का आकार m×s होगा और इसकी गणना नीचे दिखाए गए दो विधियों से की जा सकती है:


 * 1) x (b × c) आव्युह गुणा के इस क्रम में एनपीएस + एमएनएस स्केलर गुणा की आवश्यकता होगी।
 * 2) (A×B)×C आव्युह गुणन के इस क्रम में mnp + mps स्केलर गणना की आवश्यकता होगी।

मान लें कि m = 10, n = 100, p = 10 और s = 1000 है। इसलिए, श्रृंखला को गुणा करने के पहले विधियाँ के लिए 1,000,000 + 1,000,000 गणनाओं की आवश्यकता होगी। दूसरे विधियाँ में केवल 10,000+100,000 गणनाओं की आवश्यकता होगी। प्रकट है, दूसरा विधि तेज है, और हमें कोष्ठक की उस व्यवस्था का उपयोग करके आव्युह को गुणा करना चाहिए।

इसलिए, हमारा निष्कर्ष यह है कि कोष्ठकों का क्रम मायने रखता है, और हमारा कार्य कोष्ठकों के इष्टतम क्रम को खोजना है।

इस बिंदु पर, हमारे पास कई विकल्प हैं, जिनमें से गतिक प्रोग्रामिंग एल्गोरिथ्म को डिजाइन करना है जो समस्या को अतिव्यापी समस्याओं में विभाजित करेगा और कोष्ठक की इष्टतम व्यवस्था की गणना करेगा। गतिक प्रोग्रामिंग समाधान नीचे प्रस्तुत किया गया है।

चलिए m[i,j] को आव्युह i से आव्युह j (अर्थात् A) में आव्युह की श्रृंखला को गुणा करने के लिए आवश्यक स्केलर गुणन की न्यूनतम संख्या कहते हैं।i × .... × एj, अर्थात मैं <= j)। हम श्रृंखला को कुछ आव्युह k पर विभाजित करते हैं, जैसे कि i <= k <j, और यह पता लगाने का प्रयास करें कि कौन सा संयोजन न्यूनतम m [i, j] उत्पन्न करता है।

सूत्र है:

if i = j, m[i,j]= 0

if i < j, m[i,j]= min over all possible values of k (m[i,k]+m[k+1,j] + )
 * $p_(i-1)$ आव्युह i का पंक्ति आयाम है,
 * $p_k$ आव्युह k का स्तंभ आयाम है,
 * $p_j$ आव्युह j का स्तंभ आयाम है।

इस सूत्र को नीचे दिखाए अनुसार कोडित किया जा सकता है, जहां इनपुट पैरामीटर चेन मेट्रिसेस की श्रृंखला है, अर्थात $A_1, A_2, ... A_n$:

function OptimalMatrixChainParenthesis(chain) n = length(chain) for i = 1, n        m[i,i] = 0    // Since it takes no calculations to multiply one matrix for len = 2, n        for i = 1, n - len + 1 j = i + len -1 m[i,j] = infinity     // So that the first calculation updates for k = i, j-1 q = m[i, k] + m[k+1, j] + if q < m[i, j]    // The new order of parentheses is better than what we had m[i, j] = q   // Update

s[i, j] = k   // Record which k to split on, i.e. where to place the parenthesis अब तक, हमने सभी संभव के लिए मूल्यों $((A_{1} × A_{2}) × A_{3}) × ... A_{n}$ की गणना की है, आव्युह i से आव्युह j तक श्रृंखला को गुणा करने के लिए गणनाओं की न्यूनतम संख्या, और हमने संबंधित विभाजन बिंदु $A_{1}×(((A_{2}×A_{3})× ... ) × A_{n})$ पर अंकित किया है। उदाहरण के लिए, यदि हम श्रृंखला को $(A_{1} × A_{2}) × (A_{3} × ... A_{n})$ द्वारा गुणा कर रहे हैं, और इस प्रकार इसका मान $m[i, j]$ और $s[i, j]$ के रूप में प्राप्त होता हैं इसका मतलब है कि आव्युह 1 से 3 के लिए कोष्ठक का इष्टतम स्थान है $(A_1\times A_2)\times A_3$ और उन आव्यूहों को गुणा करने के लिए 100 अदिश गणनाओं की आवश्यकता होगी।

यह एल्गोरिद्म टेबल m[, ] और s[, ] तैयार करेगा जिसमें i और j के सभी संभावित मानों की प्रविष्टियां होंगी। संपूर्ण श्रृंखला के लिए अंतिम समाधान m [1, n] है, जो s [1, n] पर संबंधित विभाजन के साथ है। समाधान को खोलना पुनरावर्ती होगा, ऊपर से प्रारंभ होकर तब तक जारी रहेगा जब तक हम आधार स्थिति तक नहीं पहुंच जाते, अर्थात एकल आव्युह का गुणन किया जाता हैं।

इसलिए अगला उद्देश्य वास्तव में श्रृंखला को विभाजित करना है, अर्थात कोष्ठक को वहां रखना है जहां वे (इष्टतम रूप से) संबंधित हैं। इस उद्देश्य के लिए हम निम्नलिखित एल्गोरिथम का उपयोग कर सकते हैं:

function PrintOptimalParenthesis(s, i, j)    if i = j         print "A"i else print "("         PrintOptimalParenthesis(s, i, s[i, j])          PrintOptimalParenthesis(s, s[i, j] + 1, j)

print ")" यह एल्गोरिदम वास्तविक गुणा के लिए उपयोगी नहीं है। परिणाम कैसा दिखता है यह देखने के लिए यह एल्गोरिथ्म सिर्फ उपयोगकर्ता के अनुकूल विधि है।

वास्तव में उचित विभाजन का उपयोग करके मेट्रिसेस को गुणा करने के लिए, हमें निम्नलिखित एल्गोरिथम की आवश्यकता है: OptimalMatrixChainParenthesis(chain from 1 to n)  // this will produce s[. ] and m[. ] "tables" OptimalMatrixMultiplication(s, chain from 1 to n) // actually multiply function OptimalMatrixMultiplication(s, i, j)  // returns the result of multiplying a chain of matrices from Ai to Aj in optimal way if i < j         // keep on splitting the chain and multiplying the matrices in left and right sides LeftSide = OptimalMatrixMultiplication(s, i, s[i, j]) RightSide = OptimalMatrixMultiplication(s, s[i, j] + 1, j)         return MatrixMultiply(LeftSide, RightSide) else if i = j         return Ai   // matrix at position i       else print "error, i <= j must hold" function MatrixMultiply(A, B)   // function that multiplies two matrices if columns(A) = rows(B) for i = 1, rows(A) for j = 1, columns(B) C[i, j] = 0 for k = 1, columns(A) C[i, j] = C[i, j] + A[i, k]*B[k, j]                return C        else

print "error, incompatible dimensions."

इतिहास
डायनेमिक प्रोग्रामिंग शब्द का उपयोग मूल रूप से 1940 के दशक में रिचर्ड बेलमैन द्वारा समस्याओं को हल करने की प्रक्रिया का वर्णन करने के लिए किया गया था, जहाँ बाद के सर्वश्रेष्ठ निर्णय खोजने की आवश्यकता होती है। 1953 तक, उन्होंने इसे आधुनिक अर्थ में परिष्कृत किया, विशेष रूप से बड़े निर्णयों के अंदर छोटी निर्णय समस्याओं को नेस्ट बनाने के लिए संदर्भित करते हुए, और उसके बाद क्षेत्र को IEEE द्वारा प्रणाली विश्लेषण और अभियांत्रिकी विषय के रूप में मान्यता दी गई। बेलमैन के योगदान को बेलमैन समीकरण के नाम से याद किया जाता है, जो गतिक प्रोग्रामिंग का केंद्रीय परिणाम है जो पुनरावर्तन (कंप्यूटर विज्ञान) रूप में अनुकूलन समस्या को पुनर्स्थापित करता है।

बेलमैन अपनी आत्मकथा, आई ऑफ द हरिकेन: एन ऑटोबायोग्राफी में डायनामिक प्रोग्रामिंग शब्द के पीछे तर्क बताते हैं:

"मैंने फॉल क्वार्टर (1950 का) रैंड में बिताया। मेरा पहला काम मल्टीस्टेज डिसीजन प्रोसेस के लिए एक नाम खोजना था। एक दिलचस्प सवाल है, "डायनेमिक प्रोग्रामिंग नाम कहां से आया?" 1950 का दशक गणितीय शोध के लिए अच्छा वर्ष नहीं था। वाशिंगटन में हमारे एक बहुत ही दिलचस्प सज्जन थे जिनका नाम विल्सन था। वह रक्षा सचिव थे, और उन्हें वास्तव में "अनुसंधान" शब्द का एक रोगात्मक भय और घृणा थी। मैं इस शब्द का हल्के में उपयोग नहीं कर रहा हूँ; मैं इसका सटीक उपयोग कर रहा हूं। अगर लोग उसकी मौजूदगी में शोध शब्द का इस्तेमाल करते तो उसका चेहरा सूज जाता, वह लाल हो जाता और वह हिंसक हो जाता। आप कल्पना कर सकते हैं कि तब उन्हें गणितीय शब्द के बारे में कैसा लगा होगा। रैंड कार्पोरेशन को वायु सेना द्वारा नियोजित किया गया था, और वायु सेना के पास अनिवार्य रूप से विल्सन उसका बॉस था। इसलिए, मुझे लगा कि मुझे विल्सन और वायु सेना को इस तथ्य से बचाने के लिए कुछ करना होगा कि मैं वास्तव में रैंड कॉर्पोरेशन के अंदर गणित कर रहा था। मैं कौन सा शीर्षक, कौन सा नाम चुन सकता हूं? सबसे पहले तो मुझे योजना बनाने में, निर्णय लेने में, सोचने में दिलचस्पी थी। लेकिन नियोजन, विभिन्न कारणों से एक अच्छा शब्द नहीं है। इसलिए मैंने "प्रोग्रामिंग" शब्द का उपयोग करने का निर्णय लिया। मैं इस विचार के पार जाना चाहता था कि यह गतिशील था, यह बहुस्तरीय था, यह समय-भिन्न था। मैंने सोचा, चलो एक तीर से दो शिकार करते हैं। आइए एक ऐसा शब्द लें जिसका शास्त्रीय भौतिक अर्थों में बिल्कुल सटीक अर्थ है, अर्थात् गतिशील। विशेषण के रूप में इसकी एक बहुत ही दिलचस्प विशेषता है, और यह है कि डायनेमिक शब्द का उपयोग एक अपमानजनक अर्थ में करना असंभव है। कुछ संयोजन के बारे में सोचने का प्रयास करें जो संभवतः इसे एक निंदनीय अर्थ देगा। यह नामुमकिन है। इस प्रकार, मैंने सोचा कि गतिशील प्रोग्रामिंग एक अच्छा नाम था। यह कुछ ऐसा था जिस पर कोई कांग्रेसी भी आपत्ति नहीं कर सकता था। इसलिए मैंने इसे अपनी गतिविधियों के लिए छतरी के रूप में इस्तेमाल किया।"

- रिचर्ड बेलमैन

समस्याओं के समय-भिन्न पहलू को पकड़ने के लिए बेलमैन द्वारा गतिक शब्द चुना गया था, और क्योंकि यह प्रभावशाली लग रहा था। प्रोग्रामिंग शब्द प्रशिक्षण या रसद के लिए सैन्य कार्यक्रम के अर्थ में, इष्टतम कार्यक्रम खोजने के लिए विधि के उपयोग को संदर्भित करता है। यह प्रयोग रैखिक प्रोग्रामिंग और गणितीय प्रोग्रामिंग वाक्यांशों के समान है, जो गणितीय अनुकूलन का पर्याय है। शब्द की उत्पत्ति की उपरोक्त व्याख्या में कमी है। जैसा कि रसेल और नॉर्विग ने अपनी किताब में उपरोक्त कहानी का प्रस्तुत करते हुए लिखा है: यह पूरी तरह से सच नहीं हो सकता, क्योंकि इस शब्द का उपयोग करने वाला उनका पहला पेपर (बेलमैन, 1952) 1953 में विल्सन के रक्षा सचिव बनने से पहले छपा था। साथ ही, [http://a2c2.org/awards/richard-e-bellman-control-heritage-award/2004-00-00t000000/harold-j-kushner हैराल्ड जे. कुश्नेरr] के भाषण में टिप्पणी है, जहां उसे बेलमैन की याद आती है। बेलमैन के बारे में बोलते हुए कुश्नर को उद्धृत करते हुए: दूसरी ओर, जब मैंने उनसे वही सवाल पूछा, तो उन्होंने उत्तर दिया कि वह डायनेमिक जोड़कर डेंटज़िग की रैखिक प्रोग्रामिंग को ऊपर उठाने का प्रयास कर रहे थे। संभवतः इसकी दोनों प्रेरणाएँ सही थीं।

डायनेमिक प्रोग्रामिंग का उपयोग करने वाले एल्गोरिदम

 * प्रोटीन-डीएनए बाइंडिंग के लिए जाली मॉडल का आवर्तक समाधान
 * परिमित-क्षितिज असतत-समय गतिक अनुकूलन समस्याओं के लिए समाधान विधि के रूप में पिछड़ा प्रेरण
 * अनंत-क्षितिज, असतत-समय, छूट, समय-अपरिवर्तनीय प्रणाली में बेलमैन समीकरण को हल करने के लिए अनिर्धारित गुणांक की विधि का उपयोग किया जा सकता है। समय-अपरिवर्तनीय गतिक अनुकूलन समस्याएं
 * कई स्ट्रिंग (कंप्यूटर साइंस) एल्गोरिदम जिनमें सबसे लंबी सामान्य अनुवर्ती समस्या, सबसे लंबी बढ़ती अनुवर्ती समस्या, सबसे लंबी सामान्य सबस्ट्रिंग समस्या, लेवेनशेटिन दूरी (दूरी संपादित करें) सम्मलित हैं
 * ग्राफ के पेड़ अपघटन पर गतिक प्रोग्रामिंग का उपयोग करके अप्रत्यक्ष ग्राफ पर कई एल्गोरिदमिक समस्याओं को बाध्य पेड़ की चौड़ाई या बाध्य क्लिक-चौड़ाई के ग्राफ के लिए कुशलतापूर्वक हल किया जा सकता है।
 * CYK एल्गोरिथम या कॉके-यंगर-कसामी (CYK) एल्गोरिथम जो यह निर्धारित करता है कि दिए गए संदर्भ-मुक्त व्याकरण द्वारा दी गई स्ट्रिंग को कैसे और कैसे उत्पन्न किया जा सकता है
 * वर्ड रैप या नुथ का वर्ड रैपिंग एल्गोरिथम जो वर्ड रैपिंग टेक्स्ट के समय रैग्डनेस को कम करता है
 * कंप्यूटर शतरंज में ट्रांसपोजिशन टेबल और खंडन सूची का उपयोग
 * Viterbi एल्गोरिथ्म (छुपे छिपा हुआ मार्कोव मॉडल के लिए उपयोग किया जाता है, और विशेष रूप से भाषण टैगिंग के भाग में)
 * अर्ली एल्गोरिथम (एक प्रकार का चार्ट पार्सर)
 * नीडलमैन-वुन्श एल्गोरिथम और जैव सूचना विज्ञान में उपयोग किए जाने वाले अन्य एल्गोरिदम, जिसमें अनुक्रम संरेखण, संरचनात्मक संरेखण, आरएनए संरचना सम्मलित है * फ्लोयड-वॉर्शल एल्गोरिथमयाफ्लोयड का ऑल-पेयर शॉर्टेस्ट पाथ एल्गोरिथम
 * श्रृंखला आव्युह गुणन के क्रम का अनुकूलन
 * सबसेट योग समस्या, नैपसैक समस्या और विभाजन समस्या समस्याओं के लिए छद्म-बहुपद समय एल्गोरिदम
 * दो समय श्रृंखला के बीच वैश्विक दूरी की गणना के लिए गतिक समय वारिंग एल्गोरिदम
 * रिलेशनल डेटाबेस क्वेरी ऑप्टिमाइज़ेशन के लिए पेट्रीसिया सेलिंगर (उर्फ आईबीएम प्रणाली आर) एल्गोरिथम
 * बी-स्पलाइन वक्रों के मूल्यांकन के लिए दे बूर अल्गोरिथम
 * क्रिकेट के खेल बाधित होने पर समस्या के समाधान के लिए डकवर्थ-लुईस पद्धति
 * मार्कोव निर्णय प्रक्रियाओं को हल करने के लिए मूल्य पुनरावृत्ति विधि
 * फोटोशॉप में चुंबक चयन उपकरण जैसे चयन विधियों के बाद कुछ ग्राफिक इमेज एज
 * अंतराल समयबद्धन समस्याओं को हल करने के लिए कुछ विधियाँ
 * ट्रैवलिंग सेल्समैन की समस्या को हल करने के कुछ विधियाँ, या तो बिल्कुल (घातीय समय में) या लगभग (जैसे बिटोनिक टूर के माध्यम से)
 * रिकर्सिव कम से कम वर्ग विधि
 * संगीत सूचना पुनर्प्राप्ति में बीट (संगीत) ट्रैकिंग
 * कृत्रिम तंत्रिका नेटवर्क के लिए अनुकूली-आलोचक प्रशिक्षण रणनीति
 * स्टीरियो विजन में उपयोग की जाने वाली पत्राचार समस्या को हल करने के लिए स्टीरियो एल्गोरिदम
 * सीम नक्काशी (सामग्री-जागरूक छवि का आकार बदलना)
 * बेलमैन-फोर्ड एल्गोरिथम ग्राफ में सबसे छोटी दूरी खोजने के लिए
 * रैखिक खोज समस्या के लिए कुछ अनुमानित समाधान विधियाँ
 * कडाने का एल्गोरिथम अधिकतम सबर्रे समस्या के लिए
 * वीन ऑटोमैटिक प्रणाली प्लानिंग (WASP) पैकेज में बिजली उत्पादन विस्तार योजनाओं का अनुकूलन

अग्रिम पठन

 * . An accessible introduction to dynamic programming in economics. MATLAB code for the book.
 * . Includes an extensive bibliography of the literature in the area, up to the year 1954.
 * . Dover paperback edition (2003), ISBN 0-486-42809-5.
 * . Especially pp. 323–69.

बाहरी संबंध

 * A Tutorial on Dynamic programming
 * MIT course on algorithms - Includes 4 video lectures on DP, lectures 19-22
 * Applied Mathematical Programming by Bradley, Hax, and Magnanti, Chapter 11
 * More DP Notes
 * King, Ian, 2002 (1987), "A Simple Introduction to Dynamic Programming in Macroeconomic Models." An introduction to dynamic programming as an important tool in economic theory.
 * Dynamic Programming: from novice to advanced A TopCoder.com article by Dumitru on Dynamic Programming
 * Algebraic Dynamic Programming – a formalized framework for dynamic programming, including an entry-level course to DP, University of Bielefeld
 * Dreyfus, Stuart, "Richard Bellman on the birth of Dynamic Programming."
 * Dynamic programming tutorial
 * A Gentle Introduction to Dynamic Programming and the Viterbi Algorithm
 * Tabled Prolog BProlog, XSB, SWI-Prolog
 * IFORS online interactive dynamic programming modules including, shortest path, traveling salesman, knapsack, false coin, egg dropping, bridge and torch, replacement, chained matrix products, and critical path problem.