गतिक क्रमादेशन

right|thumb|300px|गतिक प्रोग्रामन का चित्रात्मक निरूपण । समया है - इष्टतम उपसंरचना (optimal substructure) का उपयोग करते हुए किसी मानचित्र में सबसे छोटा मार्ग पता करना। इसमें सरल रेखा ऐसे मार्ग को दिखाती है जिसमें बीच में दूसरा मार्ग नहीं निकलता ; तथा तरंगित रेखा किन्हीं दो बिन्दुओं के बीच सबसे छोटा मार्ग को निरुपित करती है। (इन दो बिन्दुओं के बीच के अन्य मार्ग नहीं दिखाए गए हैं जो अपेक्षाकृत बड़ी दूरी वाले हैं।)। मोटी रेखा में जो मार्ग दिखाया गया है वह आरम्भ से लेकर लक्ष्य तक का सबसे छोटा मार्ग है।

गणित, प्रबन्धन विज्ञान, अर्थशास्त्र, बायोइन्फॉर्मैटिक्स और कम्प्यूटर विज्ञान में गतिक क्रमादेशन या गतिक प्रोग्रामन (डाइनैमिक प्रोग्रामिंग) जटिल समस्याओं को सरल चरणों में तोड़कर हल करने के लिए एक विधि है। इसे 'गतिक इष्टतमीकरण' (डायनैमिक ऑप्टिमाइजेशन) भी कहते हैं। इसका उपयोग इष्टतमकरण (optimization) में होता है और प्रोग्रामन में ऐसी कलनविधियाँ (एल्गोरिद्म) डिजाइन करने में होता है जो कम समय में समस्या का हल निकलने में सहायक होतीं है। गतिक प्रोग्रामन का विकास १९५० के दशक में रिचर्ड बेलमैन (Richard Bellman) ने किया था। 

यह उन समस्याओं पर लागू है जो अपनी तरह की छोटी समस्याओं के अतिव्यापन (Overlapping) और प्रतिवर्तन (recursion) को प्रदर्शित करती हैं। जिन स्मस्याओं पर यह लागू होती है, यह विधि सहज (naive) तरीकों से भी कम समय लेती है। 

गतिक क्रमादेशन में एक बड़ी समस्या को सबसे पहले छोटी-छोटी (सरल) उपसमस्याओं के रूप में बदला जाता है। इसके बाद इन सरल समस्याओं को केवल एक बार हल किया जाता है तथा इनके हलों को संगृहीत (स्टोर) कर लिया जाता है। इस काम के लिये स्मृति-आधारित डेटा-स्ट्रक्चर का उपयोग किया जाता है। अगली बार जब भी वही उपसमस्या सामने आती है तो उसको पुनः हल करने के बजाय उसके संगृहीत हल को ले लिया जाता है। इस प्रकार कुछ स्मृति का अतिरिक्त उपयोग करके गणना में लगने वाले समय की बचत की जाती है। 

उदाहरण के लिए, फिबोनाकी अनुक्रम के nवें सदस्य की गणना दो तरह से की जा सकती है।
; साधारण विधि से

 function fib(n)
 if n <= 1 return n
 return fib(n − 1) + fib(n − 2)

मान लिया कि हमें codice_1 प्राप्त करना है। इसमें देख सकते हैं कि एक ऐसा 'काल ट्री' बनाते हैं जो एक ही फलन को कई बार 'काल' करता है। देखिए-

# codice_1
# codice_3
# codice_4
# codice_5
# codice_6

जैसे कि, codice_7 का मान तीन बार निकाला गया है। यदि ५ के बजाय बड़ी संख्या का उदाहरण लिया जाय तो एक ही गणना और भी अनेक बार करनी पड़ेगी। इस कारण इसमें बहुत अधिक समय लगेगा।

; 'ऊपर से नीचे' गतिक प्रोग्रामन द्वारा

 var m := map(0 → 0, 1 → 1)
 function fib(n)
 if "key n is not in "map m 
 m[n] := fib(n − 1) + fib(n − 2)
 return m[n]

इस तकनीक में जिन मानों की गणना की गयी है उन्हें भण्डारित (save) भी कर दिया गया है। 

; 'नीचे से ऊपर' गतिक प्रोग्रामन द्वारा
इस विधि में हम छोटे मानों के लिए codice_8 की गणना से शुरू करते हैं और उनका उपयोग करते हुए बड़े मानों के लिए के codice_8 का मान निकालते हैं। इस विधि में भी O("n") समय लगता है , किन्तु इसमें भण्डारण के लिए नियत जगह (O(1)) लगती है जबकि 'ऊपर से नीचे' वाली विधि में भण्डारण के लिए O("n") जगह लगती है।

 function fib(n)
 if n = 0
 return 0
 else
 var previousFib := 0, currentFib := 1
 repeat n − 1 times "// loop is skipped if n = 1"
 var newFib := previousFib + currentFib
 previousFib := currentFib
 currentFib := newFib
 return currentFib

ऊपर के दोनों उदाहरणों में हम codice_7 की गणना केवल एक बर ही कर रहे हैं (बहुत बार नहीं)। फिर इसका उपयोग codice_11 उरcodice_12 दोनों की गणना करने के लिए कर रहे हैं।