পাঠ ৩১ · ৪৪-এর মধ্যে · মডিউল ৬
Home / Courses / Discrete Mathematics / Master Theorem

ডিভাইড-অ্যান্ড-কনকার রিকারেন্স ও Master Theorem

Divide-and-conquer recurrences & the Master Theorem
৯ মিনিট পড়া মধ্যবর্তী · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • ডিভাইড-অ্যান্ড-কনকার রিকারেন্সের সাধারণ রূপ $T(n)=aT(n/b)+f(n)$-এর প্রতিটি অংশের অর্থ
  • Master Theorem-এর তিনটি কেস — নিখুঁত শর্তসহ
  • মার্জ সর্ট, বাইনারি সার্চ ও একটি তৃতীয় উদাহরণে থিওরেমের প্রয়োগ
  • কীভাবে $n^{\log_b a}$ গণনা করে সঠিক কেস চিহ্নিত করতে হয়

১ · ডিভাইড-অ্যান্ড-কনকার রিকারেন্সের সাধারণ রূপ

L29-এ আমরা দেখেছি $T(n)=2T(n/2)+n$ মার্জ সর্টের রানটাইম মডেল করে। এটি আরও সাধারণভাবে লেখা যায় —

$$T(n) = a \cdot T(n/b) + f(n), \qquad a \geq 1,\ b > 1$$

এখানে $a$ হলো প্রতিবার কতগুলো সাব-প্রবলেমে বিভক্ত হচ্ছে তার সংখ্যা, $b$ হলো প্রতিটি সাব-প্রবলেম মূল ইনপুটের কত ভাগের এক ভাগ (যেমন $b=2$ মানে অর্ধেক), এবং $f(n)$ হলো ভাগ করা (split/divide) এবং ফলাফল একত্র করা (combine) — এই দুই কাজে যত সময় লাগে তার পরিমাণ (রিকার্সিভ কল বাদে)।

মাস্টার থিওরেম কী সমস্যার সমাধান করে

L30-এর ক্যারেক্টারিস্টিক ইকুয়েশন পদ্ধতি শুধু $a_n = a_{n-1}+\dots$ ধরনের রিকারেন্সে কাজ করে ($n-1$, $n-2$ — বিয়োগ)। কিন্তু $T(n/2)$-এর মতো ভাগ-ভিত্তিক রিকারেন্সে সেই পদ্ধতি সরাসরি প্রযোজ্য নয়। Master TheoremMaster Theorem$T(n)=aT(n/b)+f(n)$ আকারের রিকারেন্সের জন্য একটি "রেসিপি" — $f(n)$-কে $n^{\log_b a}$-এর সাথে তুলনা করে সরাসরি তিনটি সম্ভাব্য কেসের একটিতে $T(n)$-এর টাইট বাউন্ড ($\Theta$) বলে দেয়, কোনো ধাপে ধাপে ডেরিভেশন ছাড়াই। ঠিক এই ধরনের রিকারেন্সের জন্য একটি সরাসরি "রেসিপি" — কোনো ধাপে ধাপে ডেরিভেশন ছাড়াই।

২ · Master Theorem — তিনটি কেস

মূল তুলনার বিন্দু হলো $n^{\log_b a}$ — এটি হলো "যদি শুধু রিকার্সিভ কলগুলোই থাকতো, combine-এর কোনো খরচ না থাকতো" তাহলে যে জটিলতা হতো। তিনটি কেস নির্ভর করে $f(n)$ এই বিন্দুর তুলনায় কেমন বাড়ে তার উপর —

কেস ১ — রিকার্সন প্রাধান্য পায়
যদি $f(n) = O\!\big(n^{\log_b a - \epsilon}\big)$ কোনো $\epsilon>0$-এর জন্য, তাহলে $T(n) = \Theta\!\big(n^{\log_b a}\big)$। ($f(n)$ তুলনামূলক ছোট — leaf নোডগুলোর মোট কাজ প্রাধান্য পায়।)
কেস ২ — সমান হারে বাড়ে
যদি $f(n) = \Theta\!\big(n^{\log_b a}\big)$, তাহলে $T(n) = \Theta\!\big(n^{\log_b a} \cdot \log n\big)$। (প্রতিটি স্তরে সমান কাজ — মোট $\log n$টি স্তর, তাই একটি $\log n$ গুণিতক যোগ হয়।)
কেস ৩ — combine প্রাধান্য পায়
যদি $f(n) = \Omega\!\big(n^{\log_b a + \epsilon}\big)$ কোনো $\epsilon>0$-এর জন্য (এবং একটি নিয়মিততা শর্ত/regularity condition সন্তুষ্ট হয়), তাহলে $T(n) = \Theta\!\big(f(n)\big)$। (root নোডের combine কাজই প্রাধান্য পায়।)
লক্ষ্য করুন — কেস ১ ও কেস ৩-এ শুধু $O$/$\Omega$ (কড়া অসমতা, একটি $\epsilon$ ফাঁক লাগবে) ব্যবহার হয়, কিন্তু কেস ২-এ সরাসরি $\Theta$ (সমান হার) ব্যবহার হয়। যদি $f(n)$ কোনো কেসেই ঠিক না বসে (যেমন $\epsilon$ ফাঁক ছাড়াই সীমানার খুব কাছাকাছি), Master Theorem প্রযোজ্য নয় — তখন অন্য পদ্ধতি (যেমন Akra-Bazzi) প্রয়োজন হতে পারে, তবে এই কোর্সে আমরা তা কভার করব না।

৩ · ওয়ার্কড উদাহরণ ১ — মার্জ সর্ট

রিকারেন্স: $T(n) = 2T(n/2) + n$।

এখানে $a=2$, $b=2$, তাই $\log_b a = \log_2 2 = 1$, অর্থাৎ তুলনার বিন্দু $n^1 = n$। আর $f(n) = n$ — যা ঠিক $n^{\log_b a} = n^1$-এর সমান। তাই এটি কেস ২।

$$T(n) = \Theta\!\big(n^1 \cdot \log n\big) = \Theta(n \log n)$$

৪ · ওয়ার্কড উদাহরণ ২ — বাইনারি সার্চ

রিকারেন্স: $T(n) = T(n/2) + O(1)$।

এখানে $a=1$, $b=2$, তাই $\log_b a = \log_2 1 = 0$, তুলনার বিন্দু $n^0 = 1$। আর $f(n) = O(1) = n^0$ — আবারও ঠিক $n^{\log_b a}$-এর সমান। তাই এটিও কেস ২।

$$T(n) = \Theta\!\big(n^0 \cdot \log n\big) = \Theta(\log n)$$

৫ · ওয়ার্কড উদাহরণ ৩ — একটি কেস ৩ উদাহরণ

রিকারেন্স: $T(n) = T(n/2) + n$।

এখানে $a=1$, $b=2$, তাই $\log_b a = 0$, তুলনার বিন্দু $n^0=1$। কিন্তু এবার $f(n) = n$, যা $n^{0+\epsilon}$-এর জন্য $\epsilon=1$ বসিয়ে $\Omega(n^{0+1}) = \Omega(n)$ শর্ত সন্তুষ্ট করে ($n$ স্পষ্টভাবে $1$-এর চেয়ে দ্রুত বাড়ে)। তাই এটি কেস ৩।

$$T(n) = \Theta(f(n)) = \Theta(n)$$

তিনটি উদাহরণ পাশাপাশি

লক্ষ্য করুন কতটা ভিন্ন ফলাফল আসে যখন শুধু $f(n)$ পরিবর্তন হয় ($a, b$ একই রেখে)। $T(n)=T(n/2)+O(1)$ দেয় $\Theta(\log n)$ (অতি দ্রুত), কিন্তু $T(n)=T(n/2)+n$ দেয় $\Theta(n)$ (অনেক ধীর) — যদিও উভয়েই মাত্র একটি সাব-প্রবলেম ($a=1$)! পার্থক্যটা পুরোপুরি combine ধাপ ($f(n)$)-এর খরচে।

Python
import math

def log_b_a(a, b):
    return math.log(a, b)

examples = [
    ("মার্জ সর্ট: T(n)=2T(n/2)+n",       2, 2, "n"),
    ("বাইনারি সার্চ: T(n)=T(n/2)+O(1)",   1, 2, "O(1) = n^0"),
    ("উদাহরণ ৩: T(n)=T(n/2)+n",          1, 2, "n"),
]

for label, a, b, f_desc in examples:
    exponent = log_b_a(a, b)
    print(f"{label}")
    print(f"  a={a}, b={b}  =>  log_b(a) = {exponent:.4f}  =>  তুলনার বিন্দু n^{exponent:.4f}")
    print(f"  f(n) = {f_desc}")

print()
print("মার্জ সর্ট      : f(n)=n = n^1.0000 = তুলনার বিন্দু       => কেস ২ => Theta(n log n)")
print("বাইনারি সার্চ   : f(n)=O(1)=n^0.0000 = তুলনার বিন্দু      => কেস ২ => Theta(log n)")
print("উদাহরণ ৩        : f(n)=n, তুলনার বিন্দু n^0 থেকে বড়        => কেস ৩ => Theta(n)")

    
কোড সেলে math.log(a, b) দিয়ে $\log_b a$ সংখ্যাগতভাবে গণনা করা হয়েছে — এটি নিশ্চিত করে যে $\log_2 2 = 1.0$ এবং $\log_2 1 = 0.0$, যা আমাদের হাতে-করা বিশ্লেষণের সাথে মিলে যায়। কোন কেস প্রযোজ্য তা ঠিক করা (যেমন $f(n)$ ঠিক $n^{\log_b a}$-এর সমান কি না) এখনো একটি গাণিতিক তুলনা, সরাসরি কোডে প্রতীকীভাবে (symbolically) যাচাই করার মতো সহজ নয় — তাই সেটি এখানে প্রিন্ট করা সিদ্ধান্ত হিসেবে দেখানো হয়েছে।
f(n) বনাম n^(log_b a) কেস ১ — f(n) ছোট Theta(n^log_b a) কেস ২ — সমান হার Theta(n^log_b a . log n) কেস ৩ — f(n) বড় Theta(f(n))
$f(n)$ তুলনার বিন্দু $n^{\log_b a}$-এর চেয়ে ছোট, সমান, নাকি বড় — তার উপর নির্ভর করে সঠিক কেস নির্বাচন হয়।
মূল কথা · Key takeaway

Master Theorem একটি সরাসরি "শর্টকাট" — ক্যারেক্টারিস্টিক ইকুয়েশনের মতো ধাপে ধাপে সমাধান না করে, শুধু $a, b, f(n)$ দেখে সরাসরি $\Theta$ বলে দেয়। এই থিওরেমটিই M8/L41-এ মার্জ সর্ট ও বাইনারি সার্চের রিয়েল-ওয়ার্ল্ড জটিলতা নির্ণয় করতে পুনরায় ব্যবহার হবে — এখানকার দুটি worked example ঠিক সেখানেই আবার ফিরে আসবে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ মার্জ সর্ট ও বাইনারি সার্চ দুটোই কেস ২-তে পড়ে, কিন্তু তাদের চূড়ান্ত জটিলতা ভিন্ন ($n\log n$ বনাম $\log n$) — কেন?

কেস ২ বলে $T(n) = \Theta(n^{\log_b a} \cdot \log n)$ — এখানে $n^{\log_b a}$ পদটি দুটি ক্ষেত্রে ভিন্ন। মার্জ সর্টে $a=2, b=2 \Rightarrow \log_b a = 1$, তাই $n^1 \cdot \log n = n \log n$। বাইনারি সার্চে $a=1, b=2 \Rightarrow \log_b a = 0$, তাই $n^0 \cdot \log n = 1 \cdot \log n = \log n$। পার্থক্যটা আসে $a$ থেকে — মার্জ সর্ট প্রতি স্তরে দুটি সাব-প্রবলেম তৈরি করে (তাই বেশি মোট কাজ), বাইনারি সার্চ প্রতি স্তরে মাত্র একটি সাব-প্রবলেমে যায় (বাকি অর্ধেক সম্পূর্ণ বাতিল হয়ে যায়)।

প্র ০২ $T(n) = T(n/2) + O(1)$ এবং $T(n) = T(n/2) + n$ — এই দুটির মধ্যে $a$ ও $b$ হুবহু একই, শুধু $f(n)$ ভিন্ন, তবু ফলাফল $\log n$ বনাম $n$ — এত বড় পার্থক্য কেন?

কারণ Master Theorem-এর কেস ২ ও কেস ৩-এর মধ্যে সিদ্ধান্তটাই সম্পূর্ণ নির্ভর করে $f(n)$ কীভাবে $n^{\log_b a}=n^0=1$-এর তুলনায় বাড়ে তার উপর। যখন $f(n)=O(1)$ (ধ্রুবক, একদম বাড়ে না) সেটি ঠিক $n^0$-এর সমান হারে থাকে — কেস ২। কিন্তু $f(n)=n$ সেই বিন্দু থেকে অনেক দ্রুত বাড়ে — কেস ৩, যেখানে সবচেয়ে ব্যয়বহুল combine ধাপই (root-এ, যেখানে $f(n)=n$ প্রয়োগ হয়) পুরো রানটাইমে প্রাধান্য বিস্তার করে, ফলে বাকি সব রিকার্সিভ কল তুলনামূলকভাবে নগণ্য হয়ে যায়।

প্র ০৩ কেস ১ ও কেস ৩-এ একটি "$\epsilon>0$" শর্ত (এবং কেস ৩-এ একটি অতিরিক্ত regularity condition) থাকে, কিন্তু কেস ২-এ থাকে না — কেন?

কেস ১ ও কেস ৩ দাবি করে $f(n)$ তুলনার বিন্দু থেকে স্পষ্টভাবে (strictly) ভিন্ন হারে বাড়ে — শুধু "একটু ভিন্ন" নয়, বরং একটি পূর্ণ পলিনমিয়াল গুণিতক ($n^\epsilon$) দ্বারা ভিন্ন। এই কড়া শর্তটি নিশ্চিত করে ফলাফল একটি পরিষ্কার $\Theta$-এ পৌঁছায়, কোনো ধোঁয়াশা ছাড়াই। কেস ২-তে $f(n)$ ইতিমধ্যেই তুলনার বিন্দুর সমান ($\Theta$) — এখানে কোনো ফাঁক ($\epsilon$) খোঁজার দরকার নেই, কারণ প্রতিটি স্তরের অবদান একই মাত্রার, শুধু স্তরসংখ্যা ($\log n$) গুণ হয়ে যোগ হয়। regularity condition (কেস ৩) একটি টেকনিক্যাল শর্ত যা নিশ্চিত করে $f(n)$ "খুব বেশি ওঠানামা করছে না" — এই কোর্সে এর গভীর ডেরিভেশনে যাওয়া হয়নি, তবে বেশিরভাগ বাস্তব $f(n)$ (যেমন পলিনমিয়াল) এই শর্ত স্বয়ংক্রিয়ভাবে পূরণ করে।

অনুশীলন

  1. কেস চিহ্নিত করুন: রিকারেন্স $T(n) = 4T(n/2) + n$-এর জন্য $a, b, \log_b a$ বের করুন এবং কোন কেস প্রযোজ্য তা নির্ধারণ করে চূড়ান্ত $\Theta$ বের করুন।

    $a=4, b=2 \Rightarrow \log_b a = \log_2 4 = 2$, তুলনার বিন্দু $n^2$। এখানে $f(n)=n=n^1$, যা $n^2$-এর চেয়ে ছোট — নির্দিষ্টভাবে $n = O(n^{2-1})$ ($\epsilon=1$ দিয়ে)। তাই এটি কেস ১, এবং $T(n) = \Theta(n^2)$।

  2. কোড প্রসারিত করুন: উপরের কোড সেলে অনুশীলন ১-এর উদাহরণ ($a=4,b=2$) যোগ করে log_b_a ফাংশন দিয়ে তুলনার বিন্দু গণনা করে প্রিন্ট করুন।

    সম্ভাব্য সমাধান:

    a, b = 4, 2
    exponent = log_b_a(a, b)
    print(f"a={a}, b={b} => log_b(a) = {exponent}")  # 2.0
    print("f(n)=n=n^1 < n^2 => কেস ১ => Theta(n^2)")

    ফলাফল 2.0 আসা উচিত, যা নিশ্চিত করে তুলনার বিন্দু $n^2$ — এবং যেহেতু $f(n)=n$ তার চেয়ে ছোট, কেস ১ প্রযোজ্য।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
রিকারেন্স সমাধান — ক্যারেক্টারিস্টিক ইকুয়েশন পদ্ধতি