1D ডিপি (1D DP)
ধরুন আপনি সিঁড়ি বেয়ে উপরে উঠছেন (climbing a staircase)। ১০ নম্বর ধাপে পৌঁছানোর জন্য, আপনাকে অবশ্যই ৯ নম্বর ধাপ (এক ধাপ উপরে) থেকে অথবা ৮ নম্বর ধাপ (দুই ধাপ উপরে) থেকে আসতে হতো। তাছাড়া অন্য কোনো উপায় নেই বা থাকার কথাও নয়। এই সাধারণ বা সিম্পল (simple) পর্যবেক্ষণটিই হলো 1D ডায়নামিক প্রোগ্রামিং (1D Dynamic Programming) এর মূল ভিত্তি বা কথা।
প্রতিবার শুরু (scratch) থেকে সম্ভাব্য প্রতিটি রুট বা পাথ (path) চেষ্টা ও পরীক্ষা করার পরিবর্তে, ডিপি (DP) মূলত বলে: "আমি ইতিমধ্যেই ৮ নম্বর এবং ৯ নম্বর ধাপে পৌঁছানোর সর্বোত্তম বা খুব ভালো উপায়গুলি বের করে ফেলেছি — তাই আমার জন্য ১০ নম্বর ধাপটি নিতান্তই সহজ বা ট্রিভিয়ালি ইজি (trivial) একটি ব্যাপার।" এভাবেই আমরা যা ইতোমধ্যে জানি সেটিকে ব্যবহার করে, টুকরো টুকরো বা একটু একটু করে নিজের কাঙ্খিত উত্তর তৈরি করি।
এর প্রবেশদ্বার বা গেটওয়ে (Gateway): ফিবোনাচি (Fibonacci)
ফিবোনাচি অনুক্রম বা সিকোয়েন্সটি (Fibonacci sequence) (০, ১, ১, ২, ৩, ৫, ৮, …) মূলত F(n) = F(n-1) + F(n-2) হিসেবে ডিফাইন বা সংজ্ঞায়িত করা থাকে। একটি সাধারণ রিকার্সিভ পদ্ধতিটি বা নেইভ রিকার্সন (naive recursive) পদ্ধতি মূলত F(5), F(6), F(7)… এর গভীরে থাকা F(3)-কে বারবার এক্সিকিউট বা পুনর্গণনা করতে থাকে আর ক্রমশ তা \(O(2^n)\) পরিমাণ বা বহুগুণ কাজে রূপান্তরিত হয়ে বিশাল এক অবস্থার সৃষ্টি করে বা স্নোবল (snowball) হয়ে যায়।
ডিপি-র (DP) ফিক্স বা সমাধানটি বেশ সোজা: F(0), F(1), F(2), … ক্রমানুসারে (order) হিসেব বা গণনা করুন এবং প্রতিটি ফলাফল সংরক্ষণ বা সেভ করে রাখুন। প্রতিটি মান পেতে বা ভ্যালুর জন্য মূলত একবার করে যোগ করতে হয়। যার সর্বমোট পরিমাণ বা টাইম: \(O(n)\)। এবং যদি আপনার শুধুমাত্র শেষের বা লাস্ট (last) দুটি মান বা ভ্যালুরই প্রয়োজন হয়, তবে আপনি সম্পূর্ন অ্যারেটির (array) বদলে মাত্র দুটি ভেরিয়েবল (variables) সংরক্ষণ করে রাখতে পারেন — যা হবে \(O(1)\) স্পেস (space)।
সিঁড়িতে আরোহণ করা (Climbing Stairs)
আপনি চাইলে একবারে ১ বা ২ ধাপ উঠতে পারেন। আপনি মোট কয়টি ভিন্ন উপায়ে n ধাপে বা স্টেপে পৌঁছাতে পারবেন? প্রতিটি i ধাপে, আপনি i-1 ধাপ বা i-2 ধাপ থেকে এসেছেন, তাই: dp[i] = dp[i-1] + dp[i-2]। এর বেস কেসগুলো (Base cases) হলো: dp[1] = 1, dp[2] = 2। এটি ঠিক ফিবোনাচির (Fibonacci) মতোই, শুধু মাত্র এটি এর থেকে এক ধাপ পিছিয়ে থাকে বা অফসেট (offset) করা থাকে।
হাউস রবার বা বাড়ি চুরি (House Robber)
ধরা যাক, একটি সারিতে কিছু বাড়ি রয়েছে আর এর প্রতিটির ভেতরে কিছু টাকা বা ডলার পরিমাণ রয়েছে, কিন্তু আপনি কোনোভাবেই পাশাপাশি থাকা দুটি বাড়িতে চুরি করতে পারবেন না। আপনাকে এর চুরির মোট লভ্যাংশ বা পরিমাণটিকে সর্বোচ্চ বা ম্যাক্সিমাইজ (maximize) করতে হবে। প্রতিটি i তম বাড়িতে আপনি একটি সুযোগ বা চয়েস পান: হয় এটিকে এড়িয়ে যান বা স্কিপ (skip) করুন (যা i-1 নম্বর বাড়ির মোট পরিমাণ বা হাল) অথবা সেটিতে চুরি করুন (দুটি বাড়ি আগে অর্থাৎ i-2 এ যে পরিমাণ টাকা ছিল, তার সাথে এই বাড়ির টাকা যোগ করুন)। রিকারেন্স (Recurrence) বা ফিরে আসা অ্যালগরিদমটি হলো: dp[i] = max(dp[i-1], dp[i-2] + nums[i])।
রোলিং-ভেরিয়েবল ট্রিক (The Rolling-Variable Trick)
যখনি dp[i] শুধু কিছু নির্দিষ্ট সংখ্যক (fixed number) ধাপ পেছনের দিকে (যেমন ধরুন সর্বশেষ ২ টির দিকে) নির্দেশ করে, তখন আপনার সম্পূর্ণ অ্যারেটির বা অ্যারের (array) কোনো প্রয়োজন নেই। শুধু ওই কয়েকটি বা ফিউ (few) ভেরিয়েবলকে (variables) সংরক্ষণ করুন, প্রতিটি ধাপে সেগুলোকে আপডেট করুন, এবং এর মাধ্যমে আপনার ব্যবহৃত স্পেস বা মেমরি স্থান \(O(n)\) থেকে সোজা \(O(1)\) এ নেমে আসবে। এই ট্রিকটি বা কৌশলটি ফিবোনাচি, ক্লাইম্বিং স্টায়ারস (climbing stairs), হাউস রবার (house robber) সহ আরও অনেক 1D ডিপি (DP) সমস্যার সমাধান করার জন্য চমৎকারভাবে কাজ করে।
হাউস রবার (House Robber) — রোলিং ভেরিয়েবলসহ (rolling variables) ডিপি
Complexity
ছোট কুইজ
পড়া চালিয়ে যান