الگوریتم مجارستانی (تخصیص بهینه)
هر کارگر را به یک کار متفاوت با کمترین هزینهی کل میدهد: تطابق را فقط روی خانههای صفرِ ماتریس کاهشیافته میسازد و هر جا گیر کرد، صفر تازه میسازد.
مسئلهی تخصیص: n کارگر و n کار با ماتریس هزینه؛ هر کارگر دقیقاً یک کار و هر کار دقیقاً یک کارگر، با کمترین هزینهی کل.
- زمان:
O(n⁴) here (O(n³) with more bookkeeping) - حافظه:
O(n²) - CLRS، بخش ۲۵.۳
سه کارگر و سه کار؛ کمترین هزینهی کل ۵ است (۱ + ۲ + ۲).
def hungarian(cost):# Assign each row (worker) to a different column (job) with the least total cost.n = len(cost)u = [min(row) for row in cost] # row potentialsv = [0] * n # column potentialsmatch = [-1] * n # match[c] is the row assigned to column cfor i in range(n):while True:# Reduced costs: the zeros are the pairs that may be matched.reduced = [[cost[r][c] - u[r] - v[c] for c in range(n)] for r in range(n)]seen_rows, seen_cols = set(), set()if augment(i, reduced, match, seen_rows, seen_cols):break# No path of zeros: lower the reduced costs just enough to make a new zero.delta = min(reduced[r][c] for r in seen_rows for c in range(n) if c not in seen_cols)for r in seen_rows:u[r] = u[r] + deltafor c in seen_cols:v[c] = v[c] - deltatotal = sum(cost[match[c]][c] for c in range(n))return totaldef augment(r, reduced, match, seen_rows, seen_cols):seen_rows.add(r)for c in range(len(reduced)):if c in seen_cols or reduced[r][c] != 0:continueseen_cols.add(c)if match[c] == -1:match[c] = rreturn Trueif augment(match[c], reduced, match, seen_rows, seen_cols):match[c] = rreturn Truereturn False
شروع اجرا
cost
| 4 | 1 | 3 |
| 2 | 0 | 5 |
| 3 | 2 | 2 |
reduced
جدول هنوز خالی است.
درخت فراخوانیهای بازگشتی
نارنجی پر = فراخوانی در حال اجرا · حاشیهی نارنجی = هنوز روی پشته · خاکستری = تمام شده
متغیرهای محلی
نارنجی = در همین گام عوض شد
cost list
Call stack
- hungarian()خط 1
توضیح
ایده
مسئلهی تخصیص: n کارگر و n کار با ماتریس هزینه؛ هر کارگر دقیقاً یک کار و هر کار دقیقاً یک کارگر، با کمترین هزینهی کل.
پتانسیلها
به هر سطر عدد u و به هر ستون عدد v میدهیم طوری که هزینهی کاهشیافته cost − u − v هیچجا منفی نباشد. اگر بتوانیم تطابقی کامل فقط از خانههای صفر بسازیم، هزینهاش Σu + Σv است و هیچ تخصیصی ارزانتر نیست؛ پس بهینه است.
الگوریتم
- برای هر سطر، روی خانههای صفر یک مسیر افزایشی پیدا کن (درست مثل تطابق دوبخشی).
- اگر پیدا نشد، کوچکترین هزینهی کاهشیافته
δرا بین سطرهای دیدهشده و ستونهای ندیده پیدا کن، بهuسطرهای دیدهشدهδاضافه و ازvستونهای دیدهشدهδکم کن. صفرهای قبلی میمانند و دستکم یک صفر تازه پیدا میشود.
در trace به چه چیزی نگاه کنی
- جدول
reducedرا ببین: صفرهایش یالهای مجاز تطابقاند و با هر تغییر پتانسیل صفر تازهای ظاهر میشود.match[c]سطرِ ستونcاست.