تخطَّ إلى المحتوى

🧮 شرح هياكل البيانات والخوارزميات

البرمجة الديناميكية — أمثلة من الحياة الواقعية

الدرس 28 من 32· ⏱ 4 دقائق قراءة

الفكرة الأساسية

لا تعيد حساب شيء حسبته سابقًا.

تخيل أنك تحسب أرقام فيبوناتشي:

فيبوناتشي بدون DP — كارثة:
fib(5)
├─ fib(4)
│  ├─ fib(3)
│  │  ├─ fib(2)
│  │  │  ├─ fib(1) = 1
│  │  │  └─ fib(0) = 0
│  │  └─ fib(1) = 1
│  └─ fib(2) ... (يعيد الحساب!)
└─ fib(3) ... (يعيد الحساب!)

نفس القيم تحسب مرارًا → O(2ⁿ)

Fibonacci — Memoization (من فوق لتحت)

نحنفظ بالنتائج في قاموس:

def fib(n, memo={}):
    if n < 2:
        return n
    if n in memo:
        return memo[n]            # 🎯 استخدم المخزّن
    memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
    return memo[n]
شجرة الاستدعاء بعد memoization:
fib(5)
├─ fib(4) — يُحسب ويُخزَّن
│  ├─ fib(3) — يُحسب ويُخزَّن
│  │  ├─ fib(2) — يُحسب ويُخزَّن
│  │  │  ├─ fib(1) = 1
│  │  │  └─ fib(0) = 0
│  │  └─ fib(1) = 1 ⚡ من المذكرة
│  └─ fib(2) = 1 ⚡ من المذكرة
└─ fib(3) = 2 ⚡ من المذكرة

O(n) بدلاً من O(2ⁿ) — تحسين هائل!

Fibonacci — Tabulation (من تحت لفوق)

نملأ جدولاً من البداية:

def fib(n):
    dp = [0, 1]          # BASE: fib(0), fib(1)
    for i in range(2, n + 1):
        dp.append(dp[i - 1] + dp[i - 2])
    return dp[n]
بناء جدول DP:

Index:  0  1  2  3  4  5
       ┌──┬──┬──┬──┬──┬──┐
       │ 0│ 1│  │  │  │  │  ← البداية
       └──┴──┴──┴──┴──┴──┘

       ┌──┬──┬──┬──┬──┬──┐
       │ 0│ 1│ 1│  │  │  │  ← dp[2] = dp[1] + dp[0]
       └──┴──┴──┴──┴──┴──┘

       ┌──┬──┬──┬──┬──┬──┐
       │ 0│ 1│ 1│ 2│ 3│ 5│  → fib(5) = 5 ✅
       └──┴──┴──┴──┴──┴──┘

مشكلة حقيبة الظهر (Knapsack)

لديك حقيبة تتسع لـ 4 كجم، وأربعة عناصر:

العنصرالوزنالقيمة
مكبر صوت4 كجم3000💰
لابتوب3 كجم2000💰
جيتار1 كجم1500💰
شاحن1 كجم1000💰

كيف تختار أقصى قيمة والوزن ≤ 4؟

جدول DP — كل خلية = أقصى قيمة لوزن معين:

         الوزن →  0    1    2    3    4
                 ┌────┬────┬────┬────┬────┐
مكبر 4kg / 3000 │  0 │  0 │  0 │  0 │3000│
                 ├────┼────┼────┼────┼────┤
لابتوب 3kg /2000 │  0 │  0 │  0 │2000│3000│
                 ├────┼────┼────┼────┼────┤
جيتار 1kg /1500 │  0 │1500│1500│2000│3500│
                 ├────┼────┼────┼────┼────┤
شاحن  1kg /1000 │  0 │1500│2500│3000│3500│
                 └────┴────┴────┴────┴────┘

القاعدة: كل خلية = max(القيمة السابقة, قيمة العنصر + قيمة الوزن المتبقي)

الحل الأمثل: 3500 — جيتار + لابتوب ✅

def knapsack(items, capacity):
    dp = [[0] * (capacity + 1) for _ in range(len(items) + 1)]

    for i in range(1, len(items) + 1):
        weight, value = items[i - 1]
        for w in range(1, capacity + 1):
            if weight <= w:
                dp[i][w] = max(
                    dp[i - 1][w],                        # لا تأخذ
                    dp[i - 1][w - weight] + value         # خذ
                )
            else:
                dp[i][w] = dp[i - 1][w]                  # الوزن أكبر من السعة
    return dp[len(items)][capacity]

أطول سلسلة جزئية مشتركة (LCS)

جدول يقارن "ABCD" مع "ACBD":

         A    C    B    D
      ┌────┬────┬────┬────┬────┐
      │  0 │  0 │  0 │  0 │  0 │
A     ├────┼────┼────┼────┼────┤
      │  0 │ 1← │ 1← │ 1← │ 1← │
B     ├────┼────┼────┼────┼────┤
      │  0 │ 1  │ 1  │ 2← │ 2← │
C     ├────┼────┼────┼────┼────┤
      │  0 │ 1  │ 2↑ │ 2  │ 2  │
D     ├────┼────┼────┼────┼────┤
      │  0 │ 1  │ 2  │ 2  │ 3↖ │
      └────┴────┴────┴────┴────┘

اتجاه الأسهم يبني السلسلة: A → B → D
LCS = "ABD"

تشبيه من الحياة — حقيبة المدرسة

تستعد لرحلة مدرسية. حقيبتك صغيرة (سعة 5 كتب). عندك 10 كتب مختلفين في الأهمية والوزن.

الطريقة الغبية: جرب كل المجموعات الممكنة → 2¹⁰ = 1024 مجموعة
الطريقة الذكية (DP): ابدأ بكتاب واحد، زد تدريجياً، واحفظ أفضل نتيجة لكل وزن

متى تستخدم DP؟

شرطان أساسيان:

  1. المسائل الفرعية متداخلة: نفس الحساب يتكرر (مثل fib)
  2. بنية فرعية مثلى: الحل الأمثل للمسألة الكبيرة يُبنى من حلول أمثل للمسائل الصغيرة
تطبيقات واقعية:
💰 الاستثمار: توزيع مبلغ محدود على استثمارات مختلفة
📦 الشحن: تعبئة حاويات بأقصى قيمة
🧬 DNA: محاذاة سلاسل جينية (LCS)
🎮 الألعاب: حساب أفضل حركة (لعبة الداما)

🎯 التالي: خوارزميات الرسم البياني — BFS و DFS بالصور.

شرح البرمجة الديناميكية — أمثلة من الحياة الواقعية — هياكل البيانات والخوارزميات بالعربي
البرمجة الديناميكية — أمثلة من الحياة الواقعيةهياكل البيانات والخوارزميات بالعربي · The Code Fix

📚 لمزيد من التعمّق في هياكل البيانات والخوارزميات، راجِع هياكل البيانات على ويكيبيديا.

هل كان هذا الدرس مفيدًا؟