AlgoVerse

افراز عدد صحیح

می‌شمارد n به چند طریق جمع عددهای مثبت می‌شود (ترتیب مهم نیست)؛ با برنامه‌ریزی پویا، قسمت‌ها یکی‌یکی مجاز می‌شوند.

افراز عدد n یعنی نوشتنش به صورت جمع عددهای مثبت، بدون توجه به ترتیب: ۴ = ۳ + ۱ = ۲ + ۲ = ۲ + ۱ + ۱ = ۱ + ۱ + ۱ + ۱ (پنج افراز).

ادامه‌ی توضیح ↓
ورودی:
n=5خروجی PDF

p(5) = 7: ۵، ۴+۱، ۳+۲، ۳+۱+۱، ۲+۲+۱، ۲+۱+۱+۱ و ۱+۱+۱+۱+۱.

  1. def partitions(n):
  2. # ways[t] = the number of ways to write t as a sum of the parts allowed so far.
  3. ways = [1] + [0] * n
  4. rows = []
  5. for part in range(1, n + 1):
  6. for total in range(part, n + 1):
  7. ways[total] = ways[total] + ways[total - part]
  8. rows.append([part] + ways)
  9. return ways[n]

ناوردا: بعد از دور part، ways[t] تعداد افرازهای t است که هیچ قسمتش از part بزرگ‌تر نیست.

شروع اجرا

part—
total—

جدول هنوز خالی است.

متغیرهای محلی

n5

نارنجی = در همین گام عوض شد

Call stack

  1. partitions()خط 1
گام ۱ از ۵۰
خط سیاه = part_done · خط نارنجی = گام کلیدیadd: 0/15 · part_done: 0/5
    توضیح

    ایده

    افراز عدد n یعنی نوشتنش به صورت جمع عددهای مثبت، بدون توجه به ترتیب: ۴ = ۳ + ۱ = ۲ + ۲ = ۲ + ۱ + ۱ = ۱ + ۱ + ۱ + ۱ (پنج افراز).

    برنامه‌ریزی پویا

    قسمت‌ها را یکی‌یکی مجاز می‌کنیم. وقتی قسمت part اضافه می‌شود، هر افراز total یا از part استفاده نمی‌کند (همان جواب قبلی)، یا دست‌کم یک part دارد (پس با حذفش افرازی از total − part می‌ماند):

    ways[total] ← ways[total] + ways[total − part]
    

    چون حلقه‌ی داخلی رو به بالا می‌رود، ways[total − part] همین حالا قسمت part را هم شامل می‌شود؛ پس یک قسمت می‌تواند چند بار بیاید. این همان الگوی مسئله‌ی خرد کردن پول است.

    در trace به چه چیزی نگاه کنی

    • هر سطر جدول کل آرایه‌ی ways بعد از مجاز شدن یک قسمت است؛ ستون آخر جواب را در هر مرحله نشان می‌دهد.