الگوریتم فلوید-وارشال: یافتن کوتاه‌ترین مسیرها بین هر جفت رأس

گاهی یک اپلیکیشن به کوتاه‌ترین فاصله بین هر جفت رأس ممکن نیاز دارد، نه فقط از یک منبع واحد. این راهنمای جامع مسئله کوتاه‌ترین مسیرهای همه‌جفت را توضیح می‌دهد، رابطه بازگشتی برنامه‌نویسی پویای ظریف پشت الگوریتم فلوید-وارشال را استخراج می‌کند، و کارایی آن را در برابر اجرای مکرر الگوریتم‌های منبع-واحد مقایسه می‌کند.

الگوریتم فلوید-وارشالکوتاه‌ترین مسیرهای همه‌جفتالگوریتم گراف برنامه‌نویسی پویا

~6 دقیقه مطالعه · آخرین به‌روزرسانی ۱۶ شهریور ۱۴۰۵

مسئله کوتاه‌ترین مسیرهای همه‌جفت

الگوریتم‌های منبع-واحد که پیش‌تر در این مجموعه بحث شدند، بلمن-فورد و الگوریتم دیجکسترا، کوتاه‌ترین مسیرها را از یک رأس منبع خاص به هر رأس دیگر پیدا می‌کنند. مسئله All-Pairs Shortest Paths (کوتاه‌ترین مسیرهای همه‌جفت) چیزی جامع‌تر می‌خواهد: کوتاه‌ترین فاصله بین هر جفت رأس مرتب ممکن در گراف.

یک رویکرد ساده: اجرای مکرر دیجکسترا

واضح‌ترین راه‌حل یک الگوریتم منبع-واحد را یک‌بار از هر رأس به‌عنوان منبع اجرا می‌کند. با استفاده از الگوریتم دیجکسترا، که پیش‌تر در این مجموعه بحث شد، برای هرکدام از V رأس به‌عنوان یک منبع، زمان اجرای کل O(V · (E + V log V)) با استفاده از یک هیپ فیبوناچی می‌دهد، که به O(V² log V + VE) ساده می‌شود. این برای گراف‌های بدون وزن‌های منفی خوب کار می‌کند، اما اگر وزن‌های منفی حاضر باشند، الگوریتم دیجکسترا نمی‌تواند استفاده شود، و اجرای بلمن-فورد از هر منبع به‌جای آن O(V²E) می‌دهد، که برای گراف‌های چگال به O(V⁴) تبدیل می‌شود — کاملاً کند.

الگوریتم فلوید-وارشال: یک رویکرد مستقیم برنامه‌نویسی پویا

به‌جای اجرای مکرر یک الگوریتم منبع-واحد، Floyd-Warshall مسئله همه‌جفت را مستقیماً با استفاده از برنامه‌نویسی پویا، که پیش‌تر در این مجموعه بحث شد، حل می‌کند، و وزن‌های یال منفی را به‌درستی مدیریت می‌کند، هرچند نه چرخه‌های منفی.

تعریف زیرمسئله

بینش کلیدی در نظر گرفتن مسیرهایی است که با کدام رأس‌های میانی می‌توانند از میان آن‌ها عبور کنند محدود شده‌اند. فرض کن d_{ij}^{(k)} کوتاه‌ترین فاصله از رأس i به رأس j باشد، با استفاده فقط از رأس‌های {1, 2, ..., k} به‌عنوان توقف‌های میانی ممکن در طول مسیر.

d_{ij}^{(0)} = w(i, j)     اگر یال (i,j) وجود داشته باشد
             = infinity    در غیر این صورت
             = 0           اگر i == j

برای k ≥ 1، رابطه بازگشتی در نظر می‌گیرد
آیا مسیر بهینه از رأس k به‌عنوان یک
توقف میانی استفاده می‌کند یا نه:

d_{ij}^{(k)} = min(
    d_{ij}^{(k-1)},                        // از رأس k استفاده نکن
    d_{ik}^{(k-1)} + d_{kj}^{(k-1)}        // از رأس k استفاده کن
)

این رابطه بازگشتی می‌گوید: کوتاه‌ترین مسیر از i به j که اجازه استفاده از رأس‌های تا k را دارد یا واقعاً اصلاً از رأس k استفاده نمی‌کند (در این صورت برابر با کوتاه‌ترین مسیر محدودشده به رأس‌های تا k-1 است)، یا دقیقاً یک‌بار از رأس k عبور می‌کند (در این صورت به کوتاه‌ترین مسیر از i به k، به‌علاوه کوتاه‌ترین مسیر از k به j، هر دو محدودشده به رأس‌های میانی تا k-1، تقسیم می‌شود).

پیاده‌سازی الگوریتم

FLOYD-WARSHALL(W, n):
  D⁽⁰⁾ = W    // با وزن‌های یال مستقیم مقداردهی اولیه کن
  برای k = 1 تا n:
      فرض کن D⁽ᵏ⁾ یک ماتریس جدید n × n باشد
      برای i = 1 تا n:
          برای j = 1 تا n:
              D⁽ᵏ⁾[i][j] = min(D⁽ᵏ⁻¹⁾[i][j],
                                D⁽ᵏ⁻¹⁾[i][k] + D⁽ᵏ⁻¹⁾[k][j])
  D⁽ⁿ⁾ را برگردان

در عمل، این با استفاده از یک ماتریس واحد که درجا به‌روزرسانی می‌شود پیاده‌سازی می‌شود، چون هر ورودی فقط به مقادیر از تکرار فعلی یا قبلی به شیوه‌ای که این ساده‌سازی را بدون تأثیر بر درستی اجازه می‌دهد، بستگی دارد.

ردیابی یک مثال کوچک

ماتریس وزن اولیه (∞ یعنی بدون یال مستقیم):
      1    2    3
1  [  0    3    ∞  ]
2  [  ∞    0    1  ]
3  [  2    ∞    0  ]

پس از در نظر گرفتن رأس 1 به‌عنوان میانی:
(بررسی اینکه آیا عبور از 1 هر جفتی را بهبود می‌دهد)
3→2 از طریق 1: 3[1] + 1[2] = 2 + 3 = 5، اما فعلی ∞ است، پس به‌روزرسانی کن

پس از در نظر گرفتن رأس 2 به‌عنوان میانی:
1→3 از طریق 2: 1[2] + 2[3] = 3 + 1 = 4، فعلی ∞ است، پس به‌روزرسانی کن

پس از در نظر گرفتن رأس 3 به‌عنوان میانی:
2→1 از طریق 3: 2[3] + 3[1] = 1 + 2 = 3، فعلی ∞ است، پس به‌روزرسانی کن

ماتریس نهایی کوتاه‌ترین مسیر بین هر جفت را شامل می‌شود

تحلیل زمان اجرا

الگوریتم از سه حلقه تودرتو تشکیل شده، هرکدام n بار اجرا می‌شوند، با کار O(1) درون درونی‌ترین حلقه، که زمان اجرای کل Θ(V³) می‌دهد. این به‌طور قابل‌توجه ساده برای پیاده‌سازی است — فقط سه حلقه تودرتو با یک مقایسه واحد — و به هیچ ساختار داده پیچیده‌ای مانند صف‌های اولویت مورد نیاز الگوریتم دیجکسترا بستگی ندارد.

مقایسه فلوید-وارشال با اجراهای مکرر منبع-واحد

فلوید-وارشال: Θ(V³)، همیشه، وزن‌های منفی را مدیریت می‌کند
دیجکسترای مکرر: O(V² log V + VE)، سریع‌تر برای گراف‌های تنک،
                    اما نمی‌تواند وزن‌های منفی را مدیریت کند
بلمن-فورد مکرر: O(V²E)، که برای گراف‌های چگال به O(V⁴) تبدیل می‌شود،
                    وزن‌های منفی را مدیریت می‌کند اما کندتر
                    از فلوید-وارشال برای گراف‌های چگال است

برای گراف‌های چگال (جایی که E نزدیک به است)، Θ(V³) فلوید-وارشال قابل‌مقایسه با یا بهتر از جایگزین‌هاست، و سادگی پیاده‌سازی‌اش، همراه با مدیریت درست وزن‌های منفی بدون نیاز به بلمن-فورد پیچیده‌تر که V بار تکرار می‌شود، آن را به انتخاب عملی تبدیل می‌کند هروقت گراف بسیار تنک نباشد.

تشخیص چرخه‌های منفی با فلوید-وارشال

مشابه با اینکه بلمن-فورد، که پیش‌تر در این مجموعه بحث شد، چرخه‌های منفی را با بررسی بهبود بیشتر پس از پایان حلقه اصلی‌اش تشخیص می‌دهد، فلوید-وارشال یک چرخه با وزن-منفی را با بررسی قطر ماتریس فاصله نهایی تشخیص می‌دهد: اگر هر D[i][i] پس از تکمیل الگوریتم منفی باشد، این یعنی یک مسیر از رأس i به خودش با وزن کل منفی وجود دارد — یک چرخه منفی که از میان i عبور می‌کند.

بازسازی مسیرهای واقعی

مشابه با ردیابی اسلاف مورد استفاده در الگوریتم‌های منبع-واحد که پیش‌تر در این مجموعه بحث شد، فلوید-وارشال می‌تواند یک ماتریس همراه از اسلاف‌ها را نگه دارد، که همراه با ماتریس فاصله در هر گام به‌روزرسانی می‌شود، و اجازه می‌دهد مسیر کوتاه‌ترین واقعی بین هر جفت رأس، نه فقط طولش، بعداً بازسازی شود.

چرا سادگی فلوید-وارشال یک قوت واقعی است

فراتر از زمان اجرای رقابتی‌اش برای گراف‌های چگال، سادگی پیاده‌سازی فلوید-وارشال — یک حلقه سه‌گانه مستقیم بدون هیچ ساختار داده کمکی — آن را بسیار کمتر مستعد خطا برای پیاده‌سازی درست در مقایسه با اجرای مکرر یک الگوریتم مبتنی بر صف اولویت از هر منبع می‌کند. این بخشی از دلیلی است که چرا فلوید-وارشال یک ابزار استاندارد برای مسائل کوتاه‌ترین مسیر همه‌جفت در عمل باقی می‌ماند، به‌ویژه برای گراف‌های چگال با اندازه متوسط جایی که زمان اجرای مکعبی‌اش کاملاً عملی باقی می‌ماند.

نوشته و پژوهش‌شده توسط دکتر شاهین صیامی

مقالات مرتبط

الگوریتم‌های نظریه اعداد: GCD، توان‌رسانی پیمانه‌ای، و RSA

رمزنگاری مدرن و بی‌شمار کاربرد الگوریتمی به تعداد کمی الگوریتم ظریف نظریه اعداد متکی است. این راهنمای جامع الگوریتم اقلیدس برای محاسبه بزرگ‌ترین مقسوم‌علیه مشترک، توان‌رسانی پیمانه‌ای سریع برای محاسبه کارآمد توان‌های بزرگ، و پایه ریاضی رمزنگاری RSA، یکی از پراستفاده‌ترین سیستم‌های رمزنگاری در جهان، را پوشش می‌دهد.

ادامه

اصول هندسه محاسباتی: جهت، تقاطع پاره‌خط، و پوسته محدب

الگوریتم‌های هندسی مسائل شامل نقاط، خطوط، و اشکال را حل می‌کنند، که در گرافیک کامپیوتری، برنامه‌ریزی مسیر رباتیک، و سیستم‌های اطلاعات جغرافیایی ظاهر می‌شوند. این راهنمای جامع آزمون جهت مبتنی بر ضرب خارجی که زیربنای تقریباً هر الگوریتم هندسی است، تشخیص تقاطع پاره‌خط ساخته‌شده روی آن آزمون، و الگوریتم اسکن گراهام برای محاسبه پوسته محدب یک مجموعه از نقاط را پوشش می‌دهد.

ادامه

الگوریتم‌های تطبیق رشته: جستجوی ساده، Rabin-Karp، و فراتر از آن

جستجو برای یک الگو درون یک متن بزرگ‌تر یکی از رایج‌ترین عملیات‌ها در محاسبات است، از ویرایشگرهای متن تا تحلیل توالی DNA. این راهنمای جامع الگوریتم تطبیق رشته ساده و بدترین‌حالت درجه‌دومش را پوشش می‌دهد، سپس استفاده ماهرانه الگوریتم Rabin-Karp از هشینگ برای دستیابی به کارایی سریع حالت‌میانگین را توضیح می‌دهد، شامل نحوه مدیریت درست برخوردهای هش.

ادامه

الگوریتم‌های تقریبی: نزدیک‌شدن اثبات‌پذیر به بهینه برای مسائل سخت

وقتی یک مسئله NP-complete اثبات شود، یک راه‌حل کارآمد دقیق بعید است وجود داشته باشد، اما این به معنای رهاکردن کامل مسئله نیست. این راهنمای جامع الگوریتم‌های تقریبی را توضیح می‌دهد، که تضمین بهینه‌بودن را در ازای تضمین کارایی معامله می‌کنند، و مسائل پوشش رأس و فروشنده دوره‌گرد را به‌عنوان مثال‌های کلاسیک با نسبت‌های تقریبی اثبات‌پذیر پوشش می‌دهد.

ادامه

NP-Completeness توضیح داده شده: P، NP، و چرا برخی مسائل در برابر راه‌حل‌های کارآمد مقاومت می‌کنند

برخی مسائل برای دهه‌ها در برابر هر تلاشی برای یک الگوریتم کارآمد مقاومت کرده‌اند، با این حال هیچ‌کس اثبات نکرده یک راه‌حل کارآمد غیرممکن است. این راهنمای جامع کلاس‌های P و NP، مفهوم تقلیل‌های زمان-چندجمله‌ای مورد استفاده برای مقایسه سختی مسئله، و چگونگی اینکه اثبات NP-complete بودن یک مسئله شواهد قوی، هرچند نه اثبات، فراهم می‌کند که هیچ الگوریتم کارآمدی وجود ندارد را توضیح می‌دهد.

ادامه

جریان بیشینه: فورد-فالکرسون و قضیه برش-کمینه/جریان-بیشینه

مسائل جریان بیشینه بیشترین توان عملیاتی ممکن از میان یک شبکه با اتصالات محدود-به-ظرفیت را مدل‌سازی می‌کنند، از لوله‌های آب تا شبکه‌های داده. این راهنمای جامع شبکه‌های جریان را معرفی می‌کند، روش فورد-فالکرسون برای یافتن جریان بیشینه با استفاده از مسیرهای تقویتی را مرور می‌کند، و قضیه ظریف برش-کمینه/جریان-بیشینه که دو مسئله به‌ظاهر متفاوت را به یکی متصل می‌کند را توضیح می‌دهد.

ادامه