AlgoVerse

تولید همه‌ی ترکیب‌ها

همه‌ی زیرمجموعه‌های k عضوی از ۱ تا n را به ترتیب لغت‌نامه‌ای می‌سازد؛ هر عضو بعدی از قبلی بزرگ‌تر است تا هیچ زیرمجموعه‌ای دو بار نیاید.

برای اینکه یک زیرمجموعه دو بار (با ترتیب‌های مختلف) نیاید، عضوها را صعودی می‌چینیم: بعد از x فقط عضوهای بزرگ‌تر از x امتحان می‌شوند.

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

زیرمجموعه‌های ۳ عضوی از ۵ عضو: C(5, 3) = ۱۰ ترکیب، از 123 تا 345.

  1. def combinations(n, k):
  2. current = []
  3. rows = []
  4. extend(1, n, k, current, rows)
  5. return len(rows)
  6. def extend(start, n, k, current, rows):
  7. if len(current) == k:
  8. rows.append(tuple(current))
  9. return
  10. # Leave room for the items still needed: the last start that can still complete a combination.
  11. last = n - (k - len(current)) + 1
  12. for x in range(start, last + 1):
  13. current.append(x)
  14. extend(x + 1, n, k, current, rows)
  15. current.pop()

ناوردا: current همیشه صعودی است و هنوز جا برای عضوهای باقی‌مانده دارد.

شروع اجرا

current—

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

درخت فراخوانی‌های بازگشتی

نارنجی پر = فراخوانی در حال اجرا · حاشیه‌ی نارنجی = هنوز روی پشته · خاکستری = تمام شده

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

n5
k3

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

Call stack

  1. combinations()خط 1
گام ۱ از ۱۶۱
خط سیاه = found · خط نارنجی = گام کلیدیchoose: 0/19 · found: 0/10 · undo: 0/19
    توضیح

    ایده

    برای اینکه یک زیرمجموعه دو بار (با ترتیب‌های مختلف) نیاید، عضوها را صعودی می‌چینیم: بعد از x فقط عضوهای بزرگ‌تر از x امتحان می‌شوند.

    هرس

    اگر هنوز r عضو لازم است، شروع از عددی بزرگ‌تر از n − r + 1 بی‌فایده است، چون عضو کافی باقی نمی‌ماند. با این مرز، هر شاخه‌ای که باز می‌شود دست‌کم به یک ترکیب می‌رسد.

    هزینه

    C(n, k) = n! / (k! (n − k)!) ترکیب، هر کدام k عضو.

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

    • درخت فراخوانی‌ها را با صفحه‌ی «تولید همه‌ی جایگشت‌ها» مقایسه کن: اینجا هر سطح فقط عددهای بزرگ‌تر را امتحان می‌کند.