الگوریتم هاپکرافت–کارپ
تطابق بیشینه در گراف دوبخشی با فازها: در هر فاز با BFS لایه میسازد و بعد چند مسیر افزایشی کوتاه و جدا از هم را با DFS پیدا میکند.
روش سادهی تطابق (مسیر افزایشی برای هر گره) در بدترین حالت O(V · E) است. هاپکرافت و کارپ (۱۹۷۳) در هر فاز چند مسیر افزایشی را با هم پیدا میکنند:
- زمان:
O(E √V) - حافظه:
O(V) - CLRS، بخش ۲۵.۱
همان کارگرها و کارهای تطابق دوبخشی؛ فاز ۱ چند جفت همزمان میسازد و فاز ۲ بقیه را با مسیرهای بلندتر پیدا میکند.
from collections import dequeINF = float("inf")def hopcroft_karp(graph, src):# Side 0 is found by two-colouring each component (the input is bipartite).side = {}for s in graph:if s in side:continueside[s] = 0stack = [s]while stack:u = stack.pop()for v, _ in graph[u]:if v not in side:side[v] = 1 - side[u]stack.append(v)left = [v for v in graph if side[v] == 0]match = {v: None for v in graph}size = 0phase = 0while True:phase = phase + 1dist, found = layers(graph, left, match)if not found:breakfor u in left:if match[u] is None:if augment(graph, u, match, dist):size = size + 1return size, matchdef layers(graph, left, match):dist = {}queue = deque()for u in left:if match[u] is None:dist[u] = 0queue.append(u)found = Falsewhile queue:u = queue.popleft()for v, _ in graph[u]:w = match[v]if w is None:found = Trueelif w not in dist:dist[w] = dist[u] + 1queue.append(w)return dist, founddef augment(graph, u, match, dist):for v, _ in graph[u]:w = match[v]if w is None:match[u] = vmatch[v] = ureturn Trueif dist.get(w) == dist[u] + 1:if augment(graph, w, match, dist):match[u] = vmatch[v] = ureturn Truedist[u] = INFreturn False
شروع اجرا
- گرهی جاری
(u) - یالهای تطابق
- یالِ در حال بررسی
درخت فراخوانیهای بازگشتی
نارنجی پر = فراخوانی در حال اجرا · حاشیهی نارنجی = هنوز روی پشته · خاکستری = تمام شده
متغیرهای محلی
نارنجی = در همین گام عوض شد
graph dict
- 'A': [('W', 1), ('X', 1)]
- 'B': [('W', 1)]
- 'C': [('X', 1), ('W', 1), ('Y', 1)]
- 'D': [('Y', 1), ('Z', 1)]
- 'W': [('A', 1), ('B', 1), ('C', 1)]
- 'X': [('A', 1), ('C', 1)]
- 'Y': [('C', 1), ('D', 1)]
- 'Z': [('D', 1)]
Call stack
- hopcroft_karp()خط 6
رشد تعداد عملیات با اندازهی ورودی
میانگین ۵ گراف تصادفی برای هر n (با seed ثابت). نشانگر توخالی = ورودی فعلی.
- phase
- layer
- ورودی فعلی (n=8)
نمایش به شکل جدول
| n | phase | layer |
|---|---|---|
| 4 | 2 | 0 |
| 8 | 2.8 | 2.4 |
| 12 | 2.4 | 2 |
| 16 | 3.2 | 8.2 |
| 20 | 3 | 8 |
توضیح
ایده
روش سادهی تطابق (مسیر افزایشی برای هر گره) در بدترین حالت O(V · E) است. هاپکرافت و کارپ (۱۹۷۳) در هر فاز چند مسیر افزایشی را با هم پیدا میکنند:
- BFS از همهی گرههای آزاد سمت چپ، گراف را لایهلایه میکند تا به یک گرهی آزاد سمت راست برسد. لایهی هر گره طول کوتاهترین مسیر افزایشی تا آن است.
- DFS از هر گرهی آزاد چپ فقط یک لایه پایینتر میرود؛ پس فقط کوتاهترین مسیرها پیدا میشوند. گرهای که به بنبست رسید برای بقیهی فاز کنار گذاشته میشود.
چرا سریع است؟
بعد از هر فاز طول کوتاهترین مسیر افزایشی دستکم یکی بیشتر میشود و میشود نشان داد فقط O(√V) فاز لازم است. هر فاز O(E) است: جمعاً O(E √V).
در trace به چه چیزی نگاه کنی
- عدد کنار گرههای چپ لایهی BFS آنهاست؛ یالهای رنگی تطابق فعلیاند.
- با سطح جزئیات «هر دور حلقه» فازها را یکییکی ببین.