الگوریتم پریم، الگوریتمی در نظریه گراف‌ها است که زیردرخت پوشای کمینه را برای یک گراف همبند وزن دار پیدا می‌کند یعنی زیرمجموعه‌ای از یال‌ها را در آن گراف می‌یابد که درختی را تشکیل می‌دهند که همه رئوس را شامل می‌شود در حالیکه مجموع وزن همه آن یال‌ها کمینه شده‌است. این الگوریتم در سال ۱۹۳۰ توسط ریاضیدانی به نام جارنیک داده شد و سپس در سال ۱۹۵۷ پریم، دانشمند علوم کامپیوتر آن را مستقل از جارنیک کشف کرد و در سال ۱۹۵۹ دایکسترا دوباره به آن دست یافت. از این رو این الگوریتم گاهی با نام الگوریتم DJP نیز شناخته می‌شود که برگرفته از اسامی دایکسترا، جارنیک و پریم است.

الگوریتم پریم، پیدا کردن درخت فراگیر مینیمال

شرح الگوریتم ویرایش

این الگوریتم مرتب‌سازی درخت را که از یک یال شروع شده‌است، افزایش می‌دهد تا جایی که که همه رئوس وارد درخت شوند.

این الگوریتم را به‌طور خلاصه می‌توان چنین شرح داد:

  • ورودی: یک گراف همبند وزن دار با مجموعه رئوس V و یالهای E
  • مقدار دهی اولیه: {Vnew = {x که Vnew مجموعه رئوس درخت پوشای کمینه در حالت آغازین را نشان می‌دهد و x یک راس دلخواه است (نقطه شروع) و
    {} = Enew که Enew بیانگر مجموعه یالهای این درخت است.
  • حلقه زیر را تا وقتی که Vnew = V تکرار کن:
    • یال (u,v) را با وزن کمینه انتخاب کن به‌طوری‌که u در Vnew قرار داشته باشد ولی v عضوی از این مجموعه نباشد (اگر چند یال باوزن یکسان وجود دارند یکی را به دلخواه انتخاب کن)
    • راس v را به Vnew و یال (u , v) رابه Enew اضافه کن.
  • خروجی :Vnew و Enew درخت پوشا. کمینه را توصیف می‌کنند.

نکته: الگوریتم پریم را به این صورت نیزمی توان بیان کرد:ابتدا گره‌ای به دلخواه انتخاب شود و سپس از بین یالهای متصل به آن یالی که با کمترین وزن انتخاب می‌شود متصل شود به گونه‌ای که حلقه ایجاد نشود. در هر مرحله یالی انتخاب می‌شود که حتماً یکی از دو سرآن جزو مسیر جواب بوده و وزن حداقل داشته باشد. پس در الگوریتم پریم دو محدودیت در هر مرحله داریم یکی آن که جنگل ایجاد نشود و دوم آنکه حلقه شکل نگیرد.

از آنجا که در الگوریتم پریم در هر مرحله فاصله هر گره با گره‌های قبلی مقایسه می‌شود پس بدیهی است که از مرتبه (n2)Ѳ می‌باشد که n تعداد رئوس گراف است.

هزینه زمانی ویرایش

یک پیاده‌سازی ساده، استفاده از نمایش گراف به صورت ماتریس مجاورت است که در آن به دنبال آرایه‌ای از وزنها باشیم و یال‌های با وزن کمینه را به مجموعه خود اضافه کنیم. این روش (O(V۲ زمان می‌برد. الگوریتم پریم بااستفاده از داده ساختار هیپ دودویی ساده و نمایش فهرست مجاورت می‌تواند در زمان (O(E log V اجرا شود که در آن E تعداد یالها و V تعداد رئوس است. استفاده از مدل پیچیده تری به نام هیپ فیبوناچی باعث می‌شود این زمان تا حد (O(E + V log V کاهش یابد. سرعت این روش به خصوص زمانی آشکار می‌شود که در گراف رابطه (E = ω(V بین رئوس و یالها برقرار باشد.

مثال ویرایش

شکل شرح
  این شکل گراف وزن دار اصلی را نشان می‌دهد. اعداد کنار هر یال بیانگر وزن آن یال هستند.
  راس D به‌طور دلخواه به عنوان نقطهٔ شروع انتخاب شده‌است. رئوس A، B، E، F همگی با یالی به D متصل هستند. A نزدیک‌ترین راس به D است بنابراین همراه با یال AD برای درخت انتخاب می‌گردد.
  راس بعدی که انتخاب می‌شود باید نزدیک‌ترین راس به A یاD باشد. فاصله B از D برابر ۹ و فاصله آن از A برابر ۷ است. فواصل E وF نیز به ترتیب ۱۵ و ۶ می‌باشد. راس F کمترین فاصله را دارد بنابراین این راس و کمان DF را انتخاب می‌کنیم.
  الگوریتم مشابه بالا ادامه می‌یابد و راس B که فاصله اش از A برابر ۷ است انتخاب می‌شود.
  در این حالت انتخاب ما بین C، E، G می‌تواند صورت گیرد. فاصله C از B برابر ۸، فاصله E ازآن برابر ۷ و فاصله G از F نیز ۱۱ است. مشاهده می‌شود که E نزدیک‌ترین راس است پس آن را همراه با کمان BE انتخاب می‌کنیم.
  در اینجا تنها رئوس C و G باقی‌مانده‌اند. فاصله C از E برابر ۵ و فاصله G از آن ۹ است پس C انتخاب می‌شود و کمان CE نیز هم‌زمان با آن وارد درخت می‌گردد.
  تنها راس باقی‌مانده G است که چون فاصله اش از E کمتر از فاصله اش تا F می‌باشد، یال EG را انتخاب می‌کنیم.
  در پایان همه رئوس انتخاب شده‌اند و درخت پوشای کمینه با رنگ سبز نشان داده شده‌است که وزنی برابر ۳۹ دارد.

شبه کد الگوریتم پریم ویرایش

مسئله:یافتن کوچکترین درخت پوشا.

ورودی: عدد صحیح n>=۲و یک گراف بدون جهت و وزن دار و پیوسته شامل n گره. گراف توسط یک آرایه دو بعدی w که سطرها و ستونهایش ار ۱ تا n شاخص دهی شده‌اند نشان داده می‌شود که در ان [w[i][j معرف وزن یال بین گره i ام و گره j ام است.

خروجی:مجموعه‌ای از یال‌ها F در یک درخت پوشای مینیمم برای گراف.

* void prim( int n,
*       const  number w[][],
* set_of_edges & F)
* {
* index i, vnear;
* number min ;
* edge e;
* index nearest[2..n];
* number distance[2..n];
* F = ∅ ;
* for (i = 2; i<=n;i++){
* nearest[i] = 1 ;
* distance[i] = W[1][i];
* }
* repeat (n-1 times){
* min=∞;
* for(i=2; i<=n; i++){
* if(0≤ distance[i] <min){
* min = distance [i];
* vnear = I ;
* }
* e= edge connecting vertices indexed by vnear and nearest[vnear  ];
* add e to F ;
* distance[vnear]= -1
* for (i=2 ; i<= n ;i++)
* if(W[i][vnear] <distance[i]){
* distance[i] = w[i][vnear];
* nearest[i] = vnear;
* }
* }
* }

اگر در لحظه شروع {y={v1 باشد، لذا [nearest[i با ۱ و [distance[i با وزن یال بین v1 و vi مقدار دهی اولیه می‌شود.همان‌طوری‌که گره‌ها به Y اضافه می‌شوند،این دو ارائه برای ارجاع گره جدید در Y به نزدیکترین گره خارج از Y ، به هنگام (update)می‌شوند.برای معین کردن گره‌ای که باید به Y اضافه شوند ،در هر تکرار ،شاخصی که مقدار distance[i]1 ان مینیمم است را محاسبه می‌کنیم. این شاخص را vnear می‌نامیم. با مقداردهی [distance[vnear به۱- ، گره با شاخص vnear به Y اضافه می‌گردد . الگوریتم بالا این روال را پیاده‌سازی می‌کند

if (y!=0)

{

   p+=e.weight;
     cout<<"("<<e.v1<<","<<e.v2<<") => W :"<<e.weight<<"\t";
      set[e.v1]=0;
 set[e.v2]=0;
 fe++;
 }
 else
 break;
 }
 return p;
 }

منابع ویرایش

پیوند به بیرون ویرایش