====== الگوریتم بلمن-فورد ====== ===== تعریف ==== الگوریتم بلمن‌-فورد راه‌کاری برای پیدا کردن کم‌وزن مسیر از رأس مشخص آغاز به بقیه رئوس در گراف جهت‌دار و وزن‌دار می‌دهد. وزن یک مسیر در گراف وزن‌دار برابر مجموع وزن یال‌های آن است. جهت‌دار نبودن یال‌ها هم مشکلی ایجاد نمی‌کند و می‌توان برای یال‌های غیر جهت‌دار دو یال فرض کرد. یکی از مزیت های این الگوریتم نسبت به [[آموزش:الگوریتم:الگوریتم_دایکسترا|الگوریتم دایکسترا]] توانایی اجرا شدن روی گراف‌ها با یال منفی است. =====کاربردها===== این الگوریتم علاوه بر پیدا کردن کوتاه‌ترین مسیر به پیدا کردن دور منفی در گراف‌ها کمک می‌کند. بنابراین استفاده‌های بیشتری از الگوریتم‌های مشابه می‌تواند داشته باشد. ===== الگوریتم ===== ابتدا روش کار این الگوریتم را بررسی می‌کنیم و سپس درستی آن را بررسی می‌کنیم. فرض کنید $1 \le ‌s \le n$ که در آن رأس ‌$s$ رأس آغاز است و فرض کنید: $$dist(s) = 0$$ و به ازای هر $v\neq s$: $$dist(v) = \infty$$ این الگوریتم به تعداد یکی کمتر از رأس ها در هر مرحله روی همه‌ی یال‌ها عملیات زیر را انجام می‌دهد: $$dist(u) = min\Big(dist(u), dist(v)+w(v, u)\Big)$$ در واقع فاصله دو سر یال را با توجه به وزن آن تصحیح می‌کند. به این عملیات در اصطلاح $Relax$ کردن یال ها می گویند. =====اثبات درستی===== درستی این الگوریتم را به استقرا ثابت می‌کنیم. فرض کنید این الگوریتم تا $i$-امین بار اجرا شدن کوتاه‌ترین فاصله تمامی رئوسی که کم‌وزن‌ترین مسیر آن‌ها حداکثر $i$ یال دارد را پیدا کند. پایه استقرا: در مرحله صفر-ام رأس آغاز فاصله‌اش صفر است؛ پس درست است. گام استقرا: هر یک از رأس‌هایی که کوتاه‌ترین مسیرشان حداکثر $i+1$ یال دارد آخرین یالشان حتما به یک رأسی است که در مرحله قبلی فاصله‌شان پیدا شده است(در واقع حداکثر از $i$ یال استفاده می‌کنند). پس بعد از $Relax$ کردن یال ها برای بار $i+1$-ام جواب تمامی رأس‌هایی که کوتاه‌ترین مسیرشان $i+1$ یالی است را پیدا کرده‌ایم. پس درستی الگوریتم ثابت می‌شود. ===== یک مثال ===== در گراف زیر، روند اجرای این الگوریتم را می‌توانید مشاهده کنید {{ :آموزش:الگوریتم:220px-bellman-ford_worst-case_example.svg.png |}} ===== پیچیدگی‌ الگوریتم ===== به ازای هر رأس باید روند بالا را طی کنیم. یعنی دنبال آن بگردیم و همه‌ی همسایه‌های آن را پیمایش کنیم. پس پیچیدگی زمانی برنامه از $O(n \times n) = O(n^2)$ است. هر چند می‌توان با استفاده از داده ساختار هرم پیاده‌سازی از $O\Big(e \times lg(n)\Big)$ ارائه داد. ===== پیاده‌سازی اولیه ===== شبه کد: function BellmanFord(list vertices, list edges, vertex s) // Step 1: initialize graph for each vertex v in vertices: if v ≠ s then dist[v] = INF // Step 2: relax edges repeatedly for i from 1 to size(vertices)-1: for each edge (u, v) with weight w in edges: if dist[u] + w < dist[v]: dist[v] = dist[u] + w ===== پیاده‌سازی ===== #include #include using namespace std; typedef pair pii; const int MAXN = 1000*100 + 10; const int INF = 1000*1000*1000; int dist[MAXN]; vector edge; vector w; int n, m; void readInput(){ cin >> n >> m; for(int i=0; i> u >> v >> z; edge.push_back(pii(u, v)); w.push_back(z); } } void bellmanFord(int s) { dist[s] = 0; for(int i=0; i ===== مسائل نمونه ===== - [[http://acm.sgu.ru/problem.php?contest=0&problem=236|مسئله‌ی ۲۳۶ سایت sgu]] ===== مراجع ===== - http://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm