ডাউন-আপ এবং টপ-ডাউনের মধ্যে পার্থক্য কী?


177

নীচে আপ পদ্ধতির (গতিশীল প্রোগ্রামিং) প্রথমে "ছোট" subproblems সময়ে খুঁজছি মধ্যে রয়েছে, এবং তারপর ছোট সমস্যার সমাধান ব্যবহার বৃহত্তর subproblems সমাধানের জন্য।

টপ-ডাউন একটি "প্রাকৃতিক পদ্ধতিতে" এবং চেক সমস্যা সমাধানের আপনি যদি আগে subproblem সমাধান হিসাব আছে মধ্যে রয়েছে।

আমি একটু বিভ্রান্ত এই দুই এর মধ্যে পার্থক্য কি?


2
সম্পর্কিত: stackoverflow.com/questions/6184869/...
aioobe

উত্তর:


247

Rev4: ব্যবহারকারী সামারনের একটি খুব স্পষ্ট মন্তব্য মন্তব্য করেছে যে সম্ভবত, এই উত্তরটি আগে বিভ্রান্ত করে শীর্ষ-ডাউন এবং নীচে আপ। মূলত এই উত্তর (রেভা 3) এবং অন্যান্য উত্তরগুলি বলেছিল যে "বটম-আপ হ'ল মেমোয়াইজেশন" ("সাব-প্রব্লেমগুলি অনুমান করুন"), এটি বিপরীত হতে পারে (যা, "শীর্ষ-ডাউন" হতে পারে "সাব-সমস্যাগুলি ধরে" এবং " নীচে আপ "" সাবপ্রব্লেমগুলি রচনা "হতে পারে)। পূর্বে, আমি মেমোয়াইজেশনটি ডায়নামিক প্রোগ্রামিংয়ের একটি সাব-টাইপের বিপরীতে ভিন্ন ধরণের গতিশীল প্রোগ্রামিং হিসাবে পড়েছি। আমি সেই মতামতটি সাবস্ক্রাইব না করেও উদ্ধৃত করেছিলাম। সাহিত্যে যথাযথ উল্লেখ পাওয়া না যাওয়া পর্যন্ত আমি এই উত্তরটিকে পরিভাষার অজ্ঞেয়বাদী হিসাবে পুনরায় লিখেছি। আমি এই উত্তরটিকে একটি সম্প্রদায় উইকিতে রূপান্তর করেছি। একাডেমিক উত্স পছন্দ করুন। রেফারেন্স এর তালিকা:} {সাহিত্য: 5 }

সংক্ষিপ্তবৃত্তি

ডায়নামিক প্রোগ্রামিং হ'ল ডুপ্লিকেট কাজকে পুনরায় গণনা এড়ানো এমন উপায়ে আপনার গণনাগুলিকে অর্ডার দেওয়ার মতো। আপনার একটি প্রধান সমস্যা রয়েছে (আপনার সাবপ্রব্লেমগুলির গাছের মূল), এবং সাবপ্রব্লেমস (সাবট্রিজ)। সাব-প্রবলেমগুলি সাধারণত পুনরাবৃত্তি হয় এবং ওভারল্যাপ হয়

উদাহরণস্বরূপ, আপনার প্রিয় ফিবোনাচির উদাহরণ বিবেচনা করুন। এটি হ'ল সাব-প্রবলেমগুলির সম্পূর্ণ গাছ, যদি আমরা একটি নিষ্পাপ পুনরাবৃত্তি কল করি:

TOP of the tree
fib(4)
 fib(3)...................... + fib(2)
  fib(2)......... + fib(1)       fib(1)........... + fib(0)
   fib(1) + fib(0)   fib(1)       fib(1)              fib(0)
    fib(1)   fib(0)
BOTTOM of the tree

(অন্য কোনও বিরল সমস্যার ক্ষেত্রে, এই গাছটি কয়েকটি শাখায় অসীম হতে পারে, এটি অবসানহীনতার প্রতিনিধিত্ব করে এবং এভাবে গাছের নীচে অসীম আকার ধারণ করতে পারে Furthermore আরও কিছু সমস্যাতে আপনি হয়ত জানেন না যে পুরো গাছটি সামনে কী দেখায় like সময়। সুতরাং, আপনার কোন কৌশল বা অ্যালগরিদম প্রয়োজন হতে পারে কোন সাব-সমস্যাগুলি প্রকাশ করা উচিত decide


স্মৃতিচারণ, ট্যাবুলেশন

গতিশীল প্রোগ্রামিংয়ের কমপক্ষে দুটি প্রধান কৌশল রয়েছে যা পারস্পরিক একচেটিয়া নয়:

  • স্মৃতিচারণ - এটি একটি ল্যাসেজ-ফায়ার পদ্ধতির: আপনি ধরে নিয়েছেন যে আপনি ইতিমধ্যে সমস্ত সাব-প্রবলেমগুলি গণনা করেছেন এবং অনুকূল মূল্যায়ন আদেশ কী তা আপনার কোনও ধারণা নেই। সাধারণত, আপনি মূল থেকে একটি পুনরাবৃত্ত কল (বা কিছু পুনরাবৃত্ত সমতুল্য) সঞ্চালন করবেন, এবং হয় আশা করেন যে আপনি সর্বোত্তম মূল্যায়ন আদেশের কাছাকাছি চলে যাবেন, বা এমন একটি প্রমাণ পাবেন যা আপনাকে অনুকূল মূল্যায়ন আদেশে পৌঁছাতে সহায়তা করবে। আপনি নিশ্চিত করবেন যে পুনরাবৃত্ত কলটি কখনই কোনও সাব-সমস্যাকে পুনরুদ্ধার করে না কারণ আপনি ফলাফলগুলি ক্যাশে করেন এবং এভাবে ডুপ্লিকেট উপ-গাছগুলি পুনরায় সংশোধন করা হয় না।

    • উদাহরণস্বরূপ: আপনি যদি ফিবোনাচি ক্রমটি গণনা করেন তবে fib(100)আপনি কেবল এটি কল করবেন এবং এটি কল করবে fib(100)=fib(99)+fib(98), যা কল করবে fib(99)=fib(98)+fib(97), ... ইত্যাদি ... যা কল করবে fib(2)=fib(1)+fib(0)=1+0=1। এরপরে এটি শেষ হয়ে যাবে fib(3)=fib(2)+fib(1), তবে এটি পুনরায় গণনা করার দরকার নেই fib(2), কারণ আমরা এটি ক্যাশে করেছি।
    • এটি গাছের শীর্ষে শুরু হয় এবং পাতা / সাবট্রিজ থেকে মূলের দিকে ফিরে সাব-সমস্যাগুলি মূল্যায়ন করে।
  • সারণী - আপনি গতিশীল প্রোগ্রামিংটিকে "টেবিল-ভর্তি" অ্যালগরিদম হিসাবে ভাবতেও পারেন (যদিও সাধারণত বহুমাত্রিক, এই 'টেবিল'-এ খুব বিরল ক্ষেত্রে * ইউক্লিডিয়ান জ্যামিতি থাকতে পারে *)। এটি স্মৃতিচারণের মতো তবে আরও সক্রিয়, এবং এতে আরও একটি পদক্ষেপ জড়িত: আপনাকে অবশ্যই সময়কালের আগে সঠিক গতিপথটি বেছে নিতে হবে যা আপনি আপনার গণনাগুলি করবেন। এটি বোঝানো উচিত নয় যে অর্ডারটি অবশ্যই স্থির হবে, তবে স্মৃতিচারণের চেয়ে আপনার আরও অনেক নমনীয়তা রয়েছে।

    • উদাহরণ: আপনি Fibonacci সম্পাদন করা হয়, আপনি এই অনুক্রমে সংখ্যার গণনা করতে চয়ন করতে পারে: fib(2), fib(3), fib(4)... যে মান ক্যাশে তাই আপনি পরবর্তী বেশী আরো সহজে গনা পারবেন না। আপনি এটিকে কোনও টেবিল (ক্যাশিংয়ের অন্য একটি রূপ) পূরণ হিসাবেও ভাবতে পারেন।
    • আমি ব্যক্তিগতভাবে 'ট্যাবুলেশন' শব্দটি খুব বেশি শুনতে পাই না, তবে এটি খুব শালীন শব্দ। কিছু লোক এই "গতিশীল প্রোগ্রামিং" বিবেচনা করে।
    • অ্যালগরিদম চালানোর আগে প্রোগ্রামার পুরো গাছটিকে বিবেচনা করে, তারপরে মূলের দিকে একটি নির্দিষ্ট ক্রমে সাব-প্রবলেমগুলি মূল্যায়নের জন্য একটি অ্যালগরিদম লেখেন, সাধারণত একটি টেবিল পূরণ করে।
    • * পাদটীকা: কখনও কখনও 'টেবিল' গ্রিডের মতো সংযোগ সহ কোনও আয়তক্ষেত্রাকার টেবিল নয় se বরং এর আরও জটিল কাঠামো থাকতে পারে যেমন গাছ বা সমস্যা কাঠামোর সাথে নির্দিষ্ট কাঠামো (যেমন মানচিত্রে বিমানের দূরত্বের মধ্যে শহরগুলি), এমনকি গ্রিডের মতো একটি ট্রেলিস ডায়াগ্রামও নেই have একটি আপ-ডাউন-বাম-ডান সংযোগের কাঠামো ইত্যাদির উদাহরণস্বরূপ, ব্যবহারকারীর 3290797 একটি গাছে সর্বাধিক স্বতন্ত্র সেট সন্ধানের একটি গতিশীল প্রোগ্রামিং উদাহরণের সাথে সংযুক্ত করেছে , যা একটি গাছের ফাঁকা অংশ পূরণ করার সাথে মিলে যায়।

(এটা একটি "গতিশীল প্রোগ্রামিং" দৃষ্টান্ত সবচেয়ে সাধারণ হয়, আমি বলতে হবে প্রোগ্রামার পুরো গাছ বলে মনে করে তারপরএকটি অ্যালগরিদম লিখেছেন যা সাব-প্রব্লেমগুলি মূল্যায়নের জন্য একটি কৌশল প্রয়োগ করে যা আপনি যা চান তার বৈশিষ্ট্যগুলি (সাধারণত সময়-জটিলতা এবং স্পেস-জটিলতার সংমিশ্রণ) অনুকূল করতে পারে। আপনার কৌশলটি অবশ্যই কোনও নির্দিষ্ট সাব-প্রব্লেম সহ কোথাও শুরু হওয়া উচিত এবং সম্ভবত সেগুলি মূল্যায়নের ফলাফলের উপর ভিত্তি করে নিজেকে খাপ খাইয়ে নিতে পারে। "ডায়নামিক প্রোগ্রামিং" এর সাধারণ অর্থে, আপনি এই সাব-প্রবলেমগুলি ক্যাশে করার চেষ্টা করতে পারেন এবং আরও সাধারণভাবে, বিভিন্ন ডেটা স্ট্রাকচারের গ্রাফের ক্ষেত্রে সম্ভবত একটি সূক্ষ্ম পার্থক্য সহ সাব-প্রবলেমগুলি পুনরায় দেখা এড়াতে চেষ্টা করুন। খুব প্রায়ই, এই ডেটা স্ট্রাকচারগুলি অ্যারে বা টেবিলের মতো তাদের মূল অংশে থাকে। সাব-সমস্যাগুলির সমাধানগুলি যদি আমাদের আর প্রয়োজন না হয় তবে তা ফেলে দেওয়া যেতে পারে))

[পূর্বে, এই উত্তরটি শীর্ষ-বনাম বনাম নীচের অংশের পরিভাষা সম্পর্কে একটি বিবৃতি দিয়েছে; মেমোয়েজেশন এবং ট্যাবুলেশন নামক দুটি মূল পদ্ধতির স্পষ্টভাবে রয়েছে যা এই শর্তাদি (যদিও পুরোপুরি নয়) এর সাথে সম্মতিযুক্ত হতে পারে। বেশিরভাগ লোকেরা সাধারণত যে শব্দটি ব্যবহার করেন তা হ'ল "ডায়নামিক প্রোগ্রামিং" এবং কিছু লোক "ডায়নামিক প্রোগ্রামিং" এর সেই বিশেষ উপ টাইপটিকে বোঝাতে "মেমোইজেশন" বলে। সম্প্রদায়টি একাডেমিক গবেষণাপত্রগুলিতে যথাযথ উল্লেখ খুঁজে না পাওয়া পর্যন্ত এই উত্তরটি শীর্ষ-ডাউন এবং নীচের অংশে কী বলে তা অস্বীকার করে। পরিশেষে, এটি পরিভাষার চেয়ে পার্থক্যটি বোঝা গুরুত্বপূর্ণ।]


সুবিধা - অসুবিধা

কোডিংয়ের সহজতা

মেমোয়েজেশন কোড করা খুব সহজ (আপনি সাধারণত * একটি "মেমোজার" টিকা বা র‌্যাপার ফাংশন লিখতে পারেন যা এটি স্বয়ংক্রিয়ভাবে এটি আপনার জন্য করে), এবং আপনার পদ্ধতির প্রথম লাইন হওয়া উচিত। সারণীর অবক্ষয়টি হ'ল আপনাকে একটি অর্ডার নিয়ে আসতে হবে।

* (এটি আসলে কেবল তখনই সহজ তবে যদি আপনি নিজেই ফাংশনটি লিখছেন, এবং / অথবা একটি অপরিষ্কার / অ-কার্যকরী প্রোগ্রামিং ভাষায় কোডিং করছেন ... উদাহরণস্বরূপ যদি কেউ ইতিমধ্যে একটি প্রাকম্পম্পিল্ড fibফাংশন লিখে থাকে তবে তা অগত্যা নিজেই পুনরাবৃত্তি কল করে এবং এই পুনরাবৃত্ত কলগুলি আপনার নতুন মেমোজাইজড ফাংশনটিকে কল করে (এবং মূল স্মৃতিবিহীন ফাংশন নয়) সুনিশ্চিত না করে আপনি যাদুতে ফাংশনটি স্মরণ করতে পারবেন না)

Recursiveness

নোট করুন যে শীর্ষ-ডাউন এবং নীচের অংশ উভয়ই পুনরাবৃত্তি বা পুনরাবৃত্তি টেবিল ভরাটের সাথে প্রয়োগ করা যেতে পারে, যদিও এটি প্রাকৃতিক নয়।

ব্যবহারিক উদ্বেগ

স্মৃতিচারণের সাহায্যে, গাছটি খুব গভীর (উদাঃ fib(10^6)) হলে আপনার স্ট্যাকের স্থান শেষ হয়ে যাবে, কারণ প্রতিটি বিলম্বিত গণনা অবশ্যই স্ট্যাকের উপরে রাখা উচিত এবং এর মধ্যে আপনার 10 ^ 6 থাকবে।

Optimality

যদি আপনি সাবপ্রব্লেমগুলি দেখার (বা চেষ্টা করার) আদেশটি যথাযথ না হন তবে পদ্ধতির সময়-অনুকূল হতে পারে না, বিশেষত যদি একটি সাবপ্রব্লেম গণনা করার একাধিক উপায় থাকে (সাধারণত ক্যাশে এটি সমাধান করবে তবে তাত্ত্বিকভাবে সম্ভব যে ক্যাশিং হতে পারে কিছু বিদেশী ক্ষেত্রে নয়)। স্মৃতিচারণ সাধারণত আপনার স্পেস-জটিলতায় আপনার সময়-জটিলতায় যোগ করবে (যেমন ট্যাবুলেশনের সাথে আপনার গণনা ছুঁড়ে দেওয়ার মতো আরও স্বাধীনতা আছে, যেমন ফিবের সাথে ট্যাবুলেশন ব্যবহারের ফলে আপনাকে ও (1) স্থান ব্যবহার করতে দেওয়া হয় তবে ফাইব সহ স্মৃতিচারণ ও (এন) ব্যবহার করে স্ট্যাক স্পেস)।

উন্নত অনুকূলিতকরণ

আপনি যদি খুব জটিল সমস্যাও করে থাকেন তবে আপনার ট্যাবুলেশন করা ছাড়া কোনও উপায় নেই (বা কমপক্ষে আপনি যেখানে যেতে চান সেখানে স্মৃতিচারণের ক্ষেত্রে আরও সক্রিয় ভূমিকা নিতে হবে)। এছাড়াও আপনি যদি এমন পরিস্থিতিতে থাকেন যেখানে অপ্টিমাইজেশন একেবারে সমালোচনামূলক এবং আপনার অবশ্যই অপ্টিমাইজ করতে হবে, ট্যাবুলেশন আপনাকে অপ্টিমাইজেশন করতে দেয় যা স্মৃতিচারণ অন্যথায় আপনাকে বুদ্ধিমানভাবে করতে দেয় না। আমার নম্র মতে, সাধারণ সফ্টওয়্যার ইঞ্জিনিয়ারিংয়ে, এই দুটি ক্ষেত্রে দুটির কোনওই সামনে আসে না, সুতরাং আমি কেবল স্মৃতি ("একটি ফাংশন যা এর উত্তরগুলিকে ক্যাশে করে") ব্যবহার না করে যদি কিছু (যেমন স্ট্যাক স্পেস) ট্যাবুলেশনকে প্রয়োজনীয় না করে ... তবে প্রযুক্তিগতভাবে স্ট্যাক ব্লাউট এড়াতে আপনি 1) ভাষাগুলিতে স্ট্যাকের আকার সীমা বৃদ্ধি করতে পারেন যা এটি অনুমতি দেয়, বা 2) আপনার স্ট্যাকটি ভার্চুয়ালাইজ করার জন্য অতিরিক্ত কাজের ধ্রুবক উপাদান খান (আইক),


আরও জটিল উদাহরণ

এখানে আমরা বিশেষ আগ্রহের উদাহরণগুলি তালিকাভুক্ত করি, এটি কেবলমাত্র সাধারণ ডিপি সমস্যা নয়, মেমোয়াইজেশন এবং ট্যাবুলেশনকে আকর্ষণীয়ভাবে পৃথক করে। উদাহরণস্বরূপ, একটি গঠন অন্যের চেয়ে অনেক সহজ হতে পারে, বা এমন একটি অপ্টিমাইজেশন হতে পারে যা মূলত ট্যাবুলেশনের প্রয়োজন:

  • দ্বি-মাত্রিক টেবিল ভর্তি অ্যালগরিদমের অ-তুচ্ছ উদাহরণ হিসাবে আকর্ষণীয় [ 4 ] সম্পাদনা-দূরত্ব গণনা করার জন্য অ্যালগরিদম

3
@ কোডার 1000001: অজগর উদাহরণগুলির জন্য, আপনি গুগল অনুসন্ধান করতে পারেন python memoization decorator; কিছু ভাষা আপনাকে ম্যাক্রো বা কোড লিখতে দেয় যা মেমোয়াইজেশন প্যাটার্নকে আবৃত করে। স্মৃতিচারণ প্যাটার্নটি "ফাংশনটি কল করার চেয়ে কিছু নয়, ক্যাশে থেকে মানটি দেখুন (যদি মানটি না থাকে তবে এটি গণনা করুন এবং এটি প্রথমে ক্যাশে যুক্ত করুন")।
নিনজাগেকো

16
আমি কাউকে এটি উল্লেখ করার মতো দেখতে পাচ্ছি না তবে আমি মনে করি টপ ডাউনের আর একটি সুবিধা হ'ল আপনি কেবল চেহারা-সারণী / ক্যাশে খুব কমই তৈরি করবেন। (অর্থাত্ আপনার যে মানগুলি প্রয়োজন সেগুলি পূরণ করুন)। সুতরাং এটি সহজ কোডিং ছাড়াও উপকার হতে পারে। অন্য কথায়, টপ ডাউনটি আপনাকে প্রকৃত চলমান সময় বাঁচাতে পারে যেহেতু আপনি সমস্ত কিছু গণনা করেন না (যদিও আপনার চলমান সময়টি বেশ ভাল হতে পারে তবে একই অ্যাসিপোটটিক চলমান সময় থাকতে পারে)। তবুও অতিরিক্ত স্ট্যাক ফ্রেমগুলি রাখতে আবার অতিরিক্ত মেমোরি প্রয়োজন (আবারও মেমরির খরচ 'মে' (কেবলমাত্র) দ্বিগুণ হলেও সংবেদনশীলভাবে এটি একই
ইনফর্মডএ

2
আমি ছাপ টপ-ডাউন পন্থা যে ওভারল্যাপিং subproblems করার ক্যাশে সমাধান একটি কৌশল বলা হয় বছরের কম বয়সী হই memoization । একটি নীচে আপ কৌশল যা একটি টেবিল পূরণ করে এবং ওভারল্যাপিং সাব-প্রব্লেমগুলি পুনর্নির্মাণকে এড়িয়ে চলে তা ট্যাবুলেশন হিসাবে উল্লেখ করা হয় । ডায়নামিক প্রোগ্রামিং ব্যবহার করার সময় এই কৌশলগুলিকে কাজে লাগানো যেতে পারে যা অনেক বড় সমস্যা সমাধানের জন্য সাব-প্রবলেমগুলি সমাধান করে। এটি এই উত্তরের সাথে বিরোধী বলে মনে হচ্ছে, যেখানে এই উত্তরটি অনেক জায়গায় ট্যাবুলেশনের পরিবর্তে গতিশীল প্রোগ্রামিং ব্যবহার করে । কে সঠিক?
সামারমন

1
@ সাম্মারন: হুম, আপনি ভাল বক্তব্য রেখেছেন। আমার সম্ভবত উইকিপিডিয়ায় আমার উত্স পরীক্ষা করা উচিত ছিল, যা আমি খুঁজে পাচ্ছি না। কিছুটা cstheory.stackexchange চেক করার পরে, আমি এখন "নীচের অংশে" বোঝাচ্ছি নীচের অংশটি আগে থেকেই জানা (ট্যাবুলেশন), এবং "টপ-ডাউন" আপনি সাবপ্রব্লেমস / সাবট্রিজের সমাধান অনুমান করছেন। সেই সময় আমি দ্বিধাবিষ্ট শব্দটি পেয়েছি এবং দ্বৈত ভিউতে বাক্যাংশগুলি ব্যাখ্যা করেছি ("নীচে আপ" আপনি সাবপ্রব্লেমগুলির সমাধান হিসাবে বিবেচনা করেছেন এবং মুখস্থ করতে পারেন, "টপ-ডাউন" আপনি জানেন যে আপনি কোন সাব-প্রবলেমগুলি সম্পর্কে আছেন এবং তা ট্যাবলেট করতে পারেন)। আমি একটি সম্পাদনায় এটিকে সম্বোধন করার চেষ্টা করব।
নিনজাগেকো

1
@ এমগিফ্রিডা: প্রোগ্রামিং ভাষার উপর নির্ভর করে স্ট্যাক স্পেসকে কখনও কখনও আলাদাভাবে বিবেচনা করা হয়। অজগর উদাহরণস্বরূপ, একটি মেমোজাইজড রিকার্সিভ ফাইব সম্পাদনা করার চেষ্টা ব্যর্থ হবে fib(513)। আমার মনে হচ্ছে ওভারলোড হওয়া পরিভাষাগুলি এখানে চলছে। 1) আপনি সবসময় আপনার আর প্রয়োজন না এমন সাব-সমস্যাগুলি ফেলে দিতে পারেন। 2) আপনি সবসময় আপনার প্রয়োজন না এমন সাব-প্রবলেম গণনা করা এড়াতে পারেন। ৩) সাব ও প্রবলেমগুলিতে স্টোর করার জন্য স্পষ্ট ডেটা স্ট্রাকচার ছাড়াই কোড করা 1 এবং 2 এর চেয়ে অনেক বেশি কঠিন হতে পারে, বা, যদি ফাংশন কলগুলির মধ্যে নিয়ন্ত্রণ প্রবাহকে অবশ্যই বুনতে হয় (আপনার স্টেট বা ধারাবাহিকতার প্রয়োজন হতে পারে)।
নিনজেকেকো

76

উপরে ডাউন এবং ডাউন আপ ডিপি একই সমস্যা সমাধানের দুটি ভিন্ন উপায়। ফাইবোনাকির সংখ্যার কম্পিউটিংয়ের জন্য মেমোমাইজড (উপরে ডাউন) বনাম গতিময় (নীচে আপ) প্রোগ্রামিং সমাধান বিবেচনা করুন।

fib_cache = {}

def memo_fib(n):
  global fib_cache
  if n == 0 or n == 1:
     return 1
  if n in fib_cache:
     return fib_cache[n]
  ret = memo_fib(n - 1) + memo_fib(n - 2)
  fib_cache[n] = ret
  return ret

def dp_fib(n):
   partial_answers = [1, 1]
   while len(partial_answers) <= n:
     partial_answers.append(partial_answers[-1] + partial_answers[-2])
   return partial_answers[n]

print memo_fib(5), dp_fib(5)

আমি ব্যক্তিগতভাবে স্মৃতিচারণ আরও অনেক প্রাকৃতিক পাই। আপনি একটি পুনরাবৃত্ত ফাংশন নিতে পারেন এবং এটি একটি যান্ত্রিক প্রক্রিয়া দ্বারা স্মারক করতে পারেন (ক্যাশে প্রথমে উত্তর উত্তর এবং সম্ভব হলে এটি ফিরিয়ে দিন, অন্যথায় এটি পুনরাবৃত্তভাবে গণনা করুন এবং তারপরে ফিরে আসার আগে আপনি ভবিষ্যতে ব্যবহারের জন্য ক্যাশে গণনাটি সংরক্ষণ করুন), তবে নীচে আপ করার সময় গতিশীল প্রোগ্রামিংয়ের জন্য আপনাকে এমন একটি অর্ডার এনকোড করা দরকার যাতে সমাধানগুলি গণনা করা হয়, যেমন কোনও ছোট সমস্যা যেটির উপর নির্ভর করে তার আগে কোনও "বড় সমস্যা" গণনা করা হয় না।


1
আহ, এখন আমি দেখতে পাচ্ছি "টপ-ডাউন" এবং "ডাউন-আপ" এর অর্থ কী; এটি আসলে স্মৃতিচারণ বনাম ডিপিকেই উল্লেখ করে। এবং ভাবতে ভাবতে আমিই সেই ব্যক্তি যিনি শিরোনামে ডিপি উল্লেখ করার জন্য প্রশ্নটি সম্পাদনা করেছিলেন ...
নিনজেকেকো

মেমোজাইজড ফাইব ভি / এস নরমাল রিরসিভ ফাইবারের রানটাইমটি কী?
সিদ্ধার্থ

ঘৃণ্য (2 ^ n) স্বাভাবিক কোজের জন্য এটি একটি পুনরাবৃত্তি গাছ আমার মনে হয়।
সিদ্ধার্থ

1
হ্যাঁ এটা লিনিয়ার! আমি পুনরাবৃত্তি গাছটি বের করেছিলাম এবং দেখেছি কোন কলগুলি এড়ানো যেতে পারে এবং মেমো_ফিব (এন - ২) কলগুলি প্রথম কল করার পরে সমস্ত এড়ানো হবে এবং তাই পুনরাবৃত্তি গাছের সমস্ত ডান শাখা কেটে দেওয়া হবে এবং এটি রৈখিক হ্রাস করব।
সিদ্ধার্থ

1
যেহেতু ডিপি মূলত একটি ফলাফলের টেবিল তৈরি করে যেখানে প্রতিটি ফলাফল একবারে গণনা করা হয়, তাই কোনও ডিপি অ্যালগরিদমের রানটাইম কল্পনা করার একটি সহজ উপায় হ'ল টেবিলটি কত বড় see এই ক্ষেত্রে, এটি আকারের এন (ইনপুট মান প্রতি এক ফলাফল) তাই ও (এন)। অন্যান্য ক্ষেত্রে এটি একটি এন ^ 2 ম্যাট্রিক্স হতে পারে, যার ফলে ও (এন ^ 2) ইত্যাদি পাওয়া যায়
জনসন ওয়াং

22

ডায়নামিক প্রোগ্রামিংয়ের একটি মূল বৈশিষ্ট্য হ'ল ওভারল্যাপিং সাব-প্রবলেমগুলির উপস্থিতি । অর্থাৎ, আপনি যে সমস্যার সমাধানের চেষ্টা করছেন সেটি সাব-প্রবলেমগুলিতে বিভক্ত হতে পারে এবং এই সাব-প্রবলেমগুলির মধ্যে অনেকগুলি সাব-প্রোব সমস্যাগুলি ভাগ করে। এটি "ভাগ করুন এবং বিজয় করুন" এর মতো, তবে আপনি একই কাজটি অনেক, বহুবার করে শেষ করেন। এই বিষয়গুলি শেখানোর বা ব্যাখ্যা করার সময় 2003 এর পরে আমি একটি উদাহরণ ব্যবহার করেছি: আপনি ফিবোনাচি সংখ্যাগুলি পুনরাবৃত্তিতে গণনা করতে পারেন ।

def fib(n):
  if n < 2:
    return n
  return fib(n-1) + fib(n-2)

আপনার পছন্দসই ভাষা ব্যবহার করুন এবং এটি চালানোর চেষ্টা করুন fib(50)। এটি একটি খুব, খুব দীর্ঘ সময় লাগবে। মোটামুটি সময় fib(50)নিজের মতো! তবে অনেক অপ্রয়োজনীয় কাজ হচ্ছে। fib(50)কল করবে fib(49)এবং fib(48), কিন্তু তারপরে উভয়ই কলিং শেষ করবে fib(47), যদিও মানটি একই। প্রকৃতপক্ষে, fib(47)তিনবার গণনা করা হবে: সরাসরি কল থেকে fib(49), সরাসরি কল থেকে fib(48)এবং অন্য একজনের সরাসরি কল fib(48)দ্বারা, যার গণনা দ্বারা উত্সাহিত হয়েছিল fib(49)... সুতরাং আপনি দেখুন, আমাদের ওভারল্যাপিং সাব-সমস্যাগুলি রয়েছে

দুর্দান্ত খবর: বহু বার একই মান গণনা করার দরকার নেই। একবার এটি গণনা করার পরে ফলাফলটি ক্যাশে করুন এবং পরের বারে ক্যাশেড মানটি ব্যবহার করুন! এটি ডায়নামিক প্রোগ্রামিংয়ের সারমর্ম। আপনি এটিকে "টপ-ডাউন", "স্মৃতিচারণ" বা অন্য যে কোনও কিছু বলতে চান। এই পদ্ধতিটি খুব স্বজ্ঞাত এবং কার্যকর করা খুব সহজ। প্রথমে কেবল একটি পুনরাবৃত্ত সমাধান সমাধান করুন, এটি ছোট পরীক্ষাগুলিতে পরীক্ষা করুন, মেমোয়েজেশন যুক্ত করুন (ইতিমধ্যে গণিত মানগুলির ক্যাচিং), এবং --- বিঙ্গো! --- তুমি পেরেছ.

সাধারণত আপনি পুনরাবৃত্তি ছাড়াই নীচ থেকে উপরে কাজ করে এমন একটি সমতুল্য পুনরাবৃত্তি প্রোগ্রামও লিখতে পারেন। এক্ষেত্রে এটি আরও প্রাকৃতিক পদ্ধতির হবে: 1 থেকে 50 পর্যন্ত লুপ আপনার সমস্ত ফিবোনাকির সংখ্যার কম্পিউটিং করার জন্য।

fib[0] = 0
fib[1] = 1
for i in range(48):
  fib[i+2] = fib[i] + fib[i+1]

যে কোনও আকর্ষণীয় দৃশ্যে নীচের অংশের সমাধানটি সাধারণত বোঝা আরও কঠিন। যাইহোক, একবার আপনি এটি বুঝতে পারলে, সাধারণত আপনি কীভাবে অ্যালগরিদম কাজ করে তার একটি আরও পরিষ্কার বড় চিত্র পাবেন d অনুশীলনে, অযৌক্তিক সমস্যাগুলি সমাধান করার সময়, আমি প্রথমে উপরে-ডাউন পদ্ধতির লেখার এবং ছোট উদাহরণগুলিতে এটি পরীক্ষার পরামর্শ দিই। তারপরে নীচের অংশের সমাধানটি লিখুন এবং আপনি একই জিনিসটি পাচ্ছেন তা নিশ্চিত করার জন্য দুটিটির সাথে তুলনা করুন। আদর্শভাবে, দুটি সমাধান স্বয়ংক্রিয়ভাবে তুলনা করুন। একটি ছোট রুটিন যে পরীক্ষার প্রচুর উৎপন্ন হবে, আদর্শভাবে লিখুন - সবনির্দিষ্ট আকার পর্যন্ত ছোট পরীক্ষা --- এবং উভয় সমাধান একই ফলাফল দেয় তা যাচাই করে। এর পরে উত্পাদনে নীচের অংশের সমাধানটি ব্যবহার করুন, তবে উপরে নীচের কোডটি রাখুন, মন্তব্য করেছেন। এটি অন্যান্য বিকাশকারীদের পক্ষে আপনি কী করছেন তা বোঝা সহজ করে তোলে: নীচের অংশের কোডটি যথেষ্ট বোধগম্য হতে পারে, এমনকি আপনি এটি লিখেছিলেন এবং আপনি ঠিক কী করছেন তা আপনি জানলেও।

অনেক অ্যাপ্লিকেশনগুলিতে পুনরাবৃত্ত কলগুলির ওভারহেডের কারণে নীচের অংশে পন্থাটি সামান্য দ্রুত হয়। স্ট্যাক ওভারফ্লো কিছু নির্দিষ্ট সমস্যাতেও সমস্যা হতে পারে এবং নোট করুন যে এটি ইনপুট ডেটার উপর খুব বেশি নির্ভর করতে পারে। কিছু ক্ষেত্রে আপনি যদি ডায়নামিক প্রোগ্রামিংটি যথেষ্ট পরিমাণে বুঝতে না পারেন তবে আপনি স্ট্যাকের ওভারফ্লোর জন্য একটি পরীক্ষা লিখতে পারবেন না, তবে কোনও এক দিন এটি এখনও ঘটতে পারে।

এখন, এমন সমস্যা রয়েছে যেখানে শীর্ষ-ডাউন পদ্ধতির একমাত্র সম্ভাব্য সমাধান কারণ সমস্যার জায়গাটি এত বড় যে সমস্ত সাব-সমস্যাগুলি সমাধান করা সম্ভব নয়। যাইহোক, "ক্যাশিং" এখনও যুক্তিসঙ্গত সময়ে কাজ করে কারণ আপনার ইনপুটটির সমাধানের জন্য কেবলমাত্র সাবপ্রব্লেমগুলির একটি ভগ্নাংশ প্রয়োজন --- তবে এটি পরিষ্কারভাবে ব্যাখ্যা করা খুব জটিল যে আপনাকে যে সাব-প্রবলেমগুলি সমাধান করতে হবে, এবং তাই লিখতে নীচে- আপ সমাধান। অন্যদিকে, এমন পরিস্থিতিতে রয়েছে যখন আপনি জানেন যে আপনাকে সমস্ত সাব-প্রবলেমগুলি সমাধান করতে হবে । এই ক্ষেত্রে যান এবং নীচে আপ ব্যবহার করুন।

আমি অনুচ্ছেদে অপ্টিমাইজেশন ওরফে ওয়ার্ড র‌্যাপ অপ্টিমাইজেশান সমস্যার জন্য শীর্ষে নীচের অংশটি ব্যবহার করব (নুথ-প্লাস লাইন-ব্রেকিং অ্যালগরিদমগুলি দেখুন; কমপক্ষে টেক্স এটি ব্যবহার করে এবং অ্যাডোব সিস্টেমগুলির কিছু সফ্টওয়্যার একই ধরণের পদ্ধতির ব্যবহার করে)। আমি ফাস্ট ফুরিয়ার ট্রান্সফর্মের জন্য নীচে ব্যবহার করব ।


হ্যালো!!! নিম্নলিখিত প্রস্তাবগুলি সঠিক কিনা তা আমি নির্ধারণ করতে চাই। - একটি ডায়নামিক প্রোগ্রামিং অ্যালগরিদমের জন্য, নীচের অংশের সাথে সমস্ত মানগুলির গণনা অসম্পূর্ণভাবে দ্রুত হয় তবে পুনরাবৃত্তি এবং স্মৃতিচারণের ব্যবহার। - একটি গতিশীল অ্যালগরিদমের সময় সর্বদা Ο (Ρ) যেখানে Ρ সাব-প্রবলেমের সংখ্যা। - এনপি-র প্রতিটি সমস্যা তাত্ক্ষণিক সময়ে সমাধান করা যেতে পারে।
মেরি স্টার

উপরের প্রস্তাবগুলি সম্পর্কে আমি কী বলতে পারি? তোমার কি কোন ধারনা আছে? @ হোসা
মেরি স্টার

@ আইভিন্ডা, (1) সর্বদা ভুল। এটি হয় একই বা অ্যাসেম্পোটোটিক্যালি ধীর গতিতে (যখন আপনার যখন সমস্ত সাব-প্রবলেমের প্রয়োজন হয় না, পুনরাবৃত্তি দ্রুততর হতে পারে)। (2) কেবলমাত্র সঠিক যদি আপনি ও (1) এর প্রতিটি সাবপ্রব্লেম সমাধান করতে পারেন। (3) একধরনের অধিকার। এনপি-র প্রতিটি সমস্যা বহুবিধ সময়ে একটি ননডেটারিস্টিক মেশিনে সমাধান করা যেতে পারে (কোয়ান্টাম কম্পিউটারের মতো, যা একসাথে একাধিক কাজ করতে পারে: এর কেক রাখুন, এবং একই সাথে এটি খান এবং উভয় ফলাফলের সন্ধান করুন)। সুতরাং এক অর্থে, এনপি-র প্রতিটি সমস্যা একটি নিয়মিত কম্পিউটারে তাত্পর্যপূর্ণ সময়ে সমাধান করা যায়। এসআইডি দ্রষ্টব্য: পি-তে সমস্ত কিছুই এনপিতে রয়েছে। যেমন দুটি পূর্ণসংখ্যার যোগ
OSA

19

উদাহরণস্বরূপ ফিবোনাচি সিরিজ নিতে দিন

1,1,2,3,5,8,13,21....

first number: 1
Second number: 1
Third Number: 2

এটি রাখার আরেকটি উপায়,

Bottom(first) number: 1
Top (Eighth) number on the given sequence: 21

প্রথম পাঁচটি ফাইবোনাকির সংখ্যার ক্ষেত্রে

Bottom(first) number :1
Top (fifth) number: 5 

এখন উদাহরণ হিসাবে পুনরাবৃত্তিযোগ্য ফিবোনাচি সিরিজের অ্যালগরিদম একবার দেখে নেওয়া যাক

public int rcursive(int n) {
    if ((n == 1) || (n == 2)) {
        return 1;
    } else {
        return rcursive(n - 1) + rcursive(n - 2);
    }
}

এখন যদি আমরা নিম্নলিখিত কমান্ড সহ এই প্রোগ্রামটি কার্যকর করি

rcursive(5);

যদি আমরা অ্যালগরিদমকে ঘনিষ্ঠভাবে দেখি তবে পঞ্চম নম্বর উত্পন্ন করার জন্য তৃতীয় এবং চতুর্থ সংখ্যা প্রয়োজন requires সুতরাং আমার পুনরাবৃত্তি আসলে উপরে থেকে শুরু হয় (5) এবং তারপরে নীচে / নিম্ন সংখ্যায় চলে যায়। এই পদ্ধতিরটি আসলে টপ-ডাউন পদ্ধতির।

একই গণনা একাধিকবার করা এড়াতে আমরা ডায়নামিক প্রোগ্রামিং কৌশল ব্যবহার করি। আমরা পূর্বে গণিত মান সংরক্ষণ করি এবং এটি পুনরায় ব্যবহার করি। এই কৌশলটিকে মেমোয়েজেশন বলা হয়। ডায়নামিক প্রোগ্রামিংয়ের আরও অনেকগুলি রয়েছে স্মৃতিচারণ যা বর্তমান সমস্যা নিয়ে আলোচনা করার প্রয়োজন নেই।

আপাদোমোস্তোক

আমাদের আসল অ্যালগরিদমটি আবার লিখতে দিন এবং মেমোজাইজড কৌশল যুক্ত করুন।

public int memoized(int n, int[] memo) {
    if (n <= 2) {
        return 1;
    } else if (memo[n] != -1) {
        return memo[n];
    } else {
        memo[n] = memoized(n - 1, memo) + memoized(n - 2, memo);
    }
    return memo[n];
}

এবং আমরা নীচের মত এই পদ্ধতি চালানো

   int n = 5;
    int[] memo = new int[n + 1];
    Arrays.fill(memo, -1);
    memoized(n, memo);

শীর্ষস্থান থেকে শুরু করে অ্যালগোরিদম হিসাবে এই সমাধানটি এখনও শীর্ষে রয়েছে এবং আমাদের শীর্ষ মান পেতে প্রতিটি ধাপে নীচে যান।

বটম-আপ

তবে, প্রশ্নটি হল, আমরা কি প্রথম দিক থেকে শুরু করতে পারি, প্রথম ফাইবোনাকির সংখ্যা থেকে তারপরে আমাদের উপরে যেতে পারি। এই কৌশলগুলি ব্যবহার করে এটি আবার লিখতে দিন,

public int dp(int n) {
    int[] output = new int[n + 1];
    output[1] = 1;
    output[2] = 1;
    for (int i = 3; i <= n; i++) {
        output[i] = output[i - 1] + output[i - 2];
    }
    return output[n];
}

এখন আমরা যদি এই অ্যালগরিদমটি খতিয়ে দেখি তবে এটি নিম্নতর মান থেকে শুরু হয় তবে শীর্ষে যান। যদি আমার 5 তম ফিবোনাচি নম্বর প্রয়োজন হয় তবে আমি আসলে 1 ম গণনা করছি, তারপরে দ্বিতীয় এবং তৃতীয়টি 5 তম নম্বর পর্যন্ত সমস্ত উপায়। এই কৌশলগুলি আসলে নীচে আপ কৌশল বলে।

শেষ দুটি, অ্যালগরিদমগুলি পূর্ণ-পূর্ণ গতিশীল প্রোগ্রামিং প্রয়োজনীয়তা। তবে একটি শীর্ষ-ডাউন এবং অন্যটি নীচে-আপ। উভয় অ্যালগরিদম একই স্থান এবং সময় জটিলতা আছে।


আমরা কী বলতে পারি যে নীচের অংশটি প্রায়শই একটি পুনরাবৃত্তির উপায়ে প্রয়োগ করা হয়?
লুইস চ্যান

নাহ, আপনি যে কোনও লুপ যুক্তিকে পুনরাবৃত্তিতে রূপান্তর করতে পারেন
আশ্বিন শর্মা ২

3

ডায়নামিক প্রোগ্রামিংকে প্রায়শই মেমোইজেশন বলা হয়!

1. স্মরণীয়করণ হ'ল টপ-ডাউন কৌশল (প্রদত্ত সমস্যাটিকে ভেঙে দিয়ে সমাধান করা শুরু করুন) এবং গতিশীল প্রোগ্রামিং হ'ল নীচের কৌশল (তুচ্ছ সাব-সমস্যা থেকে সমাধান দেওয়া শুরু করা, প্রদত্ত সমস্যার দিকে)

২.ডিপি বেস কেস (গুলি) থেকে শুরু করে সমাধানটি সন্ধান করে এবং উপরের দিকে কাজ করে। ডিপি সমস্ত উপ-সমস্যা সমাধান করে, কারণ এটি নীচে-আপ করে

স্মৃতিচারণের বিপরীতে যা কেবলমাত্র প্রয়োজনীয় সাব-সমস্যা সমাধান করে

  1. ডিপি-র ক্ষতিকারক-সময় ব্রুট-ফোর্স সমাধানগুলি বহু-কালীন অ্যালগরিদমে রূপান্তরিত করার সম্ভাবনা রয়েছে।

  2. ডিপি অনেক বেশি দক্ষ হতে পারে কারণ এর পুনরাবৃত্তি

বিপরীতে, মেমোয়েজেশন অবশ্যই পুনরাবৃত্তির কারণে (প্রায়শই তাৎপর্যপূর্ণ) ওভারহেডের জন্য দিতে হবে।

আরও সহজ কথা, মেমোয়েজেশন সমস্যাটি সমাধানের জন্য টপ-ডাউন পদ্ধতির ব্যবহার করে অর্থাৎ এটি মূল (মূল) সমস্যার সাথে শুরু করে এরপরে এটি সাব-সমস্যায় বিভক্ত হয় এবং একইভাবে এই উপ-সমস্যাগুলি সমাধান করে। এই পদ্ধতির ক্ষেত্রে একই উপ-সমস্যাটি একাধিকবার ঘটতে পারে এবং আরও সিপিইউ চক্র গ্রহণ করতে পারে, তাই সময়ের জটিলতা বাড়িয়ে তোলে। ডায়নামিক প্রোগ্রামিংয়ে একই উপ-সমস্যাটি একাধিকবার সমাধান করা হবে না তবে পূর্ববর্তী ফলাফলটি সমাধানটি অনুকূল করতে ব্যবহৃত হবে।


4
এটি সত্য নয়, মেমোয়েজেশন একটি ক্যাশে ব্যবহার করে যা আপনাকে সময়
ইনফর্মডএ

3

টপ ডাউন ডাউন অ্যাপ্রোচটি কেবল সাব সমস্যাগুলিকে বারবার কল করার জন্য পুনরাবৃত্তি ব্যবহার করে
যেখানে ডাউন আপ অ্যাপ্রোচ হিসাবে কোনওটিকে কল না করেই একক ব্যবহার করে এবং তাই এটি আরও দক্ষ।


1

নীচে নীচে থাকা সম্পাদনা দূরত্ব সমস্যার ডিপি ভিত্তিক সমাধান নীচে দেওয়া হয়েছে। আমি আশা করি এটি ডায়নামিক প্রোগ্রামিংয়ের পৃথিবী বুঝতে সহায়তা করবে:

public int minDistance(String word1, String word2) {//Standard dynamic programming puzzle.
         int m = word2.length();
            int n = word1.length();


     if(m == 0) // Cannot miss the corner cases !
                return n;
        if(n == 0)
            return m;
        int[][] DP = new int[n + 1][m + 1];

        for(int j =1 ; j <= m; j++) {
            DP[0][j] = j;
        }
        for(int i =1 ; i <= n; i++) {
            DP[i][0] = i;
        }

        for(int i =1 ; i <= n; i++) {
            for(int j =1 ; j <= m; j++) {
                if(word1.charAt(i - 1) == word2.charAt(j - 1))
                    DP[i][j] = DP[i-1][j-1];
                else
                DP[i][j] = Math.min(Math.min(DP[i-1][j], DP[i][j-1]), DP[i-1][j-1]) + 1; // Main idea is this.
            }
        }

        return DP[n][m];
}

আপনি আপনার বাড়িতে এর পুনরাবৃত্তিমূলক বাস্তবায়ন সম্পর্কে ভাবতে পারেন। আপনি যদি এর আগে এমন কিছু সমাধান না করে থাকেন তবে এটি বেশ ভাল এবং চ্যালেঞ্জিং।


1

টপ-ডাউন : এখন অবধি গণিত মানের সন্ধান করা এবং যখন বেস শর্তটি পূরণ হয় তখন ফলাফলটি ফিরিয়ে দেয়।

int n = 5;
fibTopDown(1, 1, 2, n);

private int fibTopDown(int i, int j, int count, int n) {
    if (count > n) return 1;
    if (count == n) return i + j;
    return fibTopDown(j, i + j, count + 1, n);
}

নীচে আপ : বর্তমান ফলাফল তার উপ-সমস্যার ফলাফলের উপর নির্ভর করে।

int n = 5;
fibBottomUp(n);

private int fibBottomUp(int n) {
    if (n <= 1) return 1;
    return fibBottomUp(n - 1) + fibBottomUp(n - 2);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.