1. 程式人生 > >Prim演算法和Kruskal演算法

Prim演算法和Kruskal演算法

    一、Prim演算法:

    Prim演算法實現的是找出一個有權重連通圖中的最小生成樹,即:具有最小權重且連線到所有結點的樹。(強調的是樹,樹是沒有迴路的)。

    Prim演算法是這樣來做的: 

    首先以一個結點作為最小生成樹的初始結點,然後以迭代的方式找出與最小生成樹中各結點權重最小邊,並加入到最小生成樹中。加入之後如果產生迴路則跳過這條邊,選擇下一個結點。當所有結點都加入到最小生成樹中之後,就找出了連通圖中的最小生成樹了。

    Prim演算法最小生成樹查詢過程:


C語言實現:

C程式碼  收藏程式碼
  1. #include <stdio.h>
      
  2.   #include <stdlib.h>  
  3.   #define maxint 1073741824  
  4.   int main()  
  5.   {  
  6.   FILE *input=fopen("input.txt","r"),*out=fopen("output.txt","w");  
  7.   int n,m,i,j,x,y,w;  
  8.   fscanf(input,"%d %d",&n,&m);  
  9.   int map[n][n],E[m][3],tree[m],Mst[n][n];  
  10.   /*Mst表示最小生成樹的鄰接矩陣,map是原圖,E是邊集,其中E[0]和E[1]是邊的兩個頂點,E[2]是邊的權值,tree是用於判斷原圖的點是否在最小生成樹中*/
      
  11.   memset(tree,0,sizeof(tree));  
  12.   for(i=0; i<n; i++)  
  13.   {  
  14.   for(j=0; j<n; j++)  
  15.   {  
  16.   map[i][j]=maxint;  
  17.   Mst[i][j]=maxint;  
  18.   }  
  19.   E[i][0]=E[i][1]=maxint;  
  20.   }  
  21.   for(i=0; i<m; i++)  
  22.   {  
  23.   fscanf(input,"%d %d %d",&x,&y,&w);  
  24.   if(w<map[x][y])  
  25.   {  
  26.   map[x][y]=w;  
  27.   map[y][x]=w;  
  28.   }  
  29.   }  
  30.   int min=maxint,next=0,now=0,k=0;  
  31.   tree[0]=1;  
  32.   for(i=0; i<n; i++)  
  33.   {  
  34.   for(j=0; j<n; j++)  
  35.   {  
  36.   if(map[now][j]!=maxint && tree[j]==0)  
  37.   {  
  38.   E[k][0]=now;  
  39.   E[k][2]=map[now][j];  
  40.   E[k++][1]=j;  
  41.   }  
  42.   }  
  43.   for(j=0; j<k; j++)  
  44.   {  
  45.   if(E[j][2]<min && tree[E[j][1]]==0)  
  46.   {  
  47.   min=E[j][2];  
  48.   x=E[j][0];  
  49.   y=E[j][1];  
  50.   next=y;  
  51.   }  
  52.   }  
  53.   tree[next]=1;  
  54.   now=next;  
  55.   Mst[x][y]=map[x][y];  
  56.   Mst[y][x]=map[y][x];  
  57.   min=maxint;  
  58.   }  
  59.   for(i=0; i<n; i++)  
  60.   {  
  61.   for(j=0; j<n; j++)  
  62.   {  
  63.   if(Mst[i][j]==maxint) //判斷兩點是否連通  
  64.   fprintf(out,"00 "); //美化輸出,不必多加探究  
  65.   else  
  66.   {  
  67.   fprintf(out,"%d ",Mst[i][j]); //輸出生成樹的鄰接矩陣,要輸出樹的自己可以根據鄰接矩陣的資料進行加工  
  68.   }  
  69.   }  
  70.   fprintf(out,"\n");  
  71.   }  
  72.   fclose(input);  
  73.   fclose(out);  
  74.   return 0;  
  75.   } // 程式未考慮不是連通圖的情況,修改很簡單,判斷生成樹的節點數量是否等於原圖的節點數量  
  76.   //如果小於(不會有大於)則本圖不是連通圖  
  77.   //其實prim和迪傑斯特拉演算法核心有相似之處  
 

 注意:
     
若候選輕邊集中的輕邊不止一條,可任選其中的一條擴充到T中。
     連通網的最小生成樹不一定是惟一的,但它們的權相等。
【例】在上圖(e)中,若選取的輕邊是(2,4)而不是(2,1)時,則得到如圖(h)所示的另一棵MST。
    
演算法特點
     該演算法的特點是當前形成的集合T始終是一棵樹。將T中U和TE分別看作紅點和紅邊集,V-U看作藍點集。演算法的每一步均是在連線紅、藍點集的紫邊中選擇一條輕邊擴充進T中。MST性質保證了此邊是安全的。T從任意的根r開始,並逐漸生長直至U=V,即T包含了 C中所有的頂點為止。MST性質確保此時的T是G的一棵MST。因為每次新增的邊是使樹中的權儘可能小,因此這是一種"貪心"的策略。
演算法分析
     該演算法的時間複雜度為O(n2)。與圖中邊數無關,該演算法適合於稠密圖。

演算法演示:

http://sjjp.tjuci.edu.cn/sjjg/DataStructure/DS/web/flashhtml/prim.htm

    二、Kruskal演算法:

    Kruskal演算法與Prim演算法的不同之處在於,Kruskal在找最小生成樹結點之前,需要對所有權重邊做從小到大排序。將排序好的權重邊依次加入到最小生成樹中,如果加入時產生迴路就跳過這條邊,加入下一條邊。當所有結點都加入到最小生成樹中之後,就找出了最小生成樹。

C語言實現:

C程式碼  收藏程式碼
  1. /* Kruskal.c 
  2.   Copyright (c) 2002, 2006 by ctu_85 
  3.   All Rights Reserved. 
  4.   */  
  5.   /* I am sorry to say that the situation of unconnected graph is not concerned */  
  6.   #include "stdio.h"  
  7.   #define maxver 10  
  8.   #define maxright 100  
  9.   int G[maxver][maxver],record=0,touched[maxver][maxver];  
  10.   int circle=0;  
  11.   int FindCircle(int,int,int,int);  
  12.   int main()  
  13.   {  
  14.   int path[maxver][2],used[maxver][maxver];  
  15.   int i,j,k,t,min=maxright,exsit=0;  
  16.   int v1,v2,num,temp,status=0;  
  17.   restart:  
  18.   printf("Please enter the number of vertex(s) in the graph:\n");  
  19.   scanf("%d",&num);  
  20.   if(num>maxver||num<0)  
  21.   {  
  22.   printf("Error!Please reinput!\n");  
  23.   goto restart;  
  24.   }  
  25.   for(j=0;j<num;j++)  
  26.   for(k=0;k<num;k++)  
  27.   {  
  28.   if(j==k)  
  29.   {  
  30.   G[j][k]=maxright;  
  31.   used[j][k]=1;  
  32.   touched[j][k]=0;  
  33.   }  
  34.   else  
  35.   if(j<k)  
  36.   {  
  37.   re:  
  38.   printf("Please input the right between vertex %d and vertex %d,if no edge exists please input -1:\n",j+1,k+1);  
  39.   scanf("%d",&temp);  
  40.   if(temp>=maxright||temp<-1)  
  41.   {  
  42.   printf("Invalid input!\n");  
  43.   goto re;  
  44.   }  
  45.   if(temp==-1)  
  46.   temp=maxright;  
  47.   G[j][k]=G[k][j]=temp;  
  48.   used[j][k]=used[k][j]=0;  
  49.   touched[j][k]=touched[k][j]=0;  
  50.   }  
  51.   }  
  52.   for(j=0;j<num;j++)  
  53.   {  
  54.   path[j][0]=0;  
  55.   path[j][1]=0;  
  56.   }  
  57.   for(j=0;j<num;j++)  
  58.   {  
  59.   status=0;  
  60.   for(k=0;k<num;k++)  
  61.   if(G[j][k]<maxright)  
  62.   {  
  63.   status=1;  
  64.   break;  
  65.   }  
  66.   if(status==0)  
  67.   break;  
  68.   }  
  69.   for(i=0;i<num-1&&status;i++)  
  70.   {  
  71.   for(j=0;j<num;j++)  
  72.   for(k=0;k<num;k++)  
  73.   if(G[j][k]<min&&!used[j][k])  
  74.   {  
  75.   v1=j;  
  76.   v2=k;  
  77.   min=G[j][k];  
  78.   }  
  79.   if(!used[v1][v2])  
  80.   {  
  81.   used[v1][v2]=1;  
  82.   used[v2][v1]=1;  
  83.   touched[v1][v2]=1;  
  84.   touched[v2][v1]=1;  
  85.   path[0]=v1;  
  86.   path[1]=v2;  
  87.   for(t=0;t<record;t++)  
  88.   FindCircle(path[t][0],path[t][0],num,path[t][0]);  
  89.   if(circle)  
  90.   {/*if a circle exsits,roll back*/  
  91.   circle=0;  
  92.   i--;  
  93.   exsit=0;  
  94.   touched[v1][v2]=0;  
  95.   touched[v2][v1]=0;  
  96.   min=maxright;  
  97.   }  
  98.   else  
  99.   {  
  100.   record++;  
  101.   min=maxright;  
  102.   }  
  103.   }  
  104.   }  
  105.   if(!status)  
  106.   printf("We cannot deal with it because the graph is not connected!\n");  
  107.   else  
  108.   {  
  109.   for(i=0;i<num-1;i++)  
  110.   printf("Path %d:vertex %d to vertex %d\n",i+1,path[0]+1,path[1]+1);  
  111.   }  
  112.   return 1;  
  113.   }  
  114.   int FindCircle(int start,int begin,int times,int pre)  
  115.   { /* to judge whether a circle is produced*/  
  116.   int i;  
  117.   for(i=0;i<times;i++)  
  118.   if(touched[begin]==1)  
  119.   {  
  120.   if(i==start&&pre!=start)  
  121.   {  
  122.   circle=1;  
  123.   return 1;  
  124.   break;  
  125.   }  
  126.   else  
  127.   if(pre!=i)  
  128.   FindCircle(start,i,times,begin);  
  129.   else  
  130.   continue;  
  131.   }  
  132.   return 1;  
  133.   }  
 

相關推薦

最小生成樹的prim演算法kruskal演算法

轉載自:勿在浮沙築高臺http://blog.csdn.net/luoshixian099/article/details/51908175 關於圖的幾個概念定義: 連通圖:在無向圖中,若任意兩個頂點vi與vj都有路徑相通,則稱該無向圖為連通圖。 強連通圖:在有向圖中,若任意兩個

python機器學習案例系列教程——最小生成樹(MST)的Prim演算法Kruskal演算法

最小生成樹MST 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 也就是說,用原圖中有的邊,連線n個節點,保證每個節點都被連線,且使用的邊的數目最少。 最小權重生成樹 在一給定

圖的最小生成樹:Prim演算法Kruskal演算法

1. 圖的最小生成樹 生成樹的定義:如果連通圖G的一個子圖是一棵包含G的所有頂點的樹,則該子圖稱為G的生成樹。 生成樹是連通圖的包含圖中的所有頂點的極小連通子圖。它並不唯一,從不同的頂點出發進行遍歷,可以得到不同的生成樹。 其中,權值最小的樹就是最小生成樹

Prim演算法Kruskal演算法理解

一:Prim演算法 Prim演算法的實現就是通過搜尋來實現的,首先找一個起始點a,然後找與起始點相關聯的所有的點中離a最近的點b,並且把這個點融入最小生成樹中,然後再比較與b相關聯的點和與a相關聯的點的距離,若可以更新點,則更新然後繼續找! 拿一道poj的題來說 You

最小生成樹演算法——Prim演算法Kruskal演算法的JS實現

之前都是看書,大部分也是c++的實現,但是搞前端不能忘了JS啊,所以JS實現一遍這兩個經典的最小生成樹演算法。 一、權重圖和最小生成樹 權重圖:圖的邊帶權重 最小生成樹:在連通圖的所有生成樹中,所有邊的權重和最小的生成樹 本文使用的圖如下: 它的最小生成樹如下:

最小生成樹的兩種經典演算法--prim演算法kruskal演算法

一個連通圖的生成樹是圖的一個極小連通子圖,它包含所有頂點,但只有足以構成樹的n-1條邊 這意味著對生成樹來說,砍去它的任何一條邊,就會使生成樹變成非連通圖,若給他增加一條邊就會形成一條迴路 最小生成樹:權值最小的那顆生成樹叫~ 最小生成樹的性質: 最小生成樹

Dijkstra演算法prim演算法 Kruskal演算法詳解

1 Dijkstra演算法問題描述:在一個圖中,給定指定頂點,求該頂點到其它頂點的最短距離。如圖所示:這是一個有向圖,現在要求解從頂點V1到其它頂點的最短距離。以上圖為例,利用Dijkstra演算法求解最短距離。步驟:(1)將所有頂點分為兩組,一組是未知的即為S,一組是已知的

貪心法--最小生成樹的Prim演算法Kruskal演算法

一,貪心法和分治法,DP法的本質不通在於:   只選擇一個子問題求解 二,貪心法的特點: ①,快 ②不能保證得到最優解 三,貪心法的關鍵是:分解方案和貪心選擇方案 以最小生成樹為例進行說明: P

Prim演算法Kruskal演算法

    一、Prim演算法:     Prim演算法實現的是找出一個有權重連通圖中的最小生成樹,即:具有最小權重且連線到所有結點的樹。(強調的是樹,樹是沒有迴路的)。     Prim演算法是這樣來做的:      首先以一個結點作為最小生成樹的初始結點,然後以迭代的方式找出與最小生成樹中各結點權

最小生成樹-Prim演算法Kruskal演算法

假設以下情景,有一塊木板,板上釘上了一些釘子,這些釘子可以由一些細繩連線起來。假設每個釘子可以通過一根或者多根細繩連線起來,那麼一定存在這樣的情況,即用最少的細繩把所有釘子連線起來。 更為實際的情景是這樣的情況,在某地分佈著N個村莊,現在需要在N個村莊之間修路,每個村莊

最小生成樹—Prim演算法Kruskal演算法 (理解)

 一個帶權連通無向圖中可能有多棵生成樹,所有生成樹中具有邊上的權值之和最小的樹稱為圖的最小生成樹。n個頂點的連通圖的生成樹有n個頂點、n-1條邊,性質如下:1.不能有迴路2.一個圖的最小生成樹不一定是

最小生成樹之prim演算法kruskal演算法

在日常生活中解決問題經常需要考慮最優的問題,而最小生成樹就是其中的一種。看了很多部落格,先總結如下,只需要您20分鐘的時間,就能完全理解。比如:有四個村莊要修四條路,讓村子能兩兩聯絡起來,這時就有最優的問題,怎樣修才是做好的,如下圖:第一個是網全圖,後三個圖的修路方案都可以1

Prim演算法Kruskal演算法(最小生成樹)

Prim演算法 1.概覽 普里姆演算法(Prim演算法),圖論中的一種演算法,可在加權連通圖裡搜尋最小生成樹。意即由此演算法搜尋到的邊子集所構成的樹中,不但包括了連通圖裡的所有頂點(英語:Vertex (graph theory)),且其所有邊的權值之和亦為最小。該演算法於1930年由捷克數學家沃伊捷赫·

最小生成樹的Prim演算法Kruskal演算法java程式碼實現

MiniSpanTree中兩個靜態函式實現了最小生成樹的Prim演算法和Kruskal演算法: package datastucture; import java.util.ArrayList; import java.util.Arrays; import java.

[從今天開始修煉資料結構]圖的最小生成樹 —— 最清楚易懂的Prim演算法kruskal演算法講解實現

接上文,研究了一下演算法之後,發現大話資料結構的程式碼風格更適合與前文中鄰接矩陣的定義相關聯,所以硬著頭皮把大話中的最小生成樹用自己的話整理了一下,希望大家能夠看懂。   一、最小生成樹     1,問題       最小生成樹要解決的是帶權圖 即 網 結構的問題,就是n個頂點,用n-1條邊把一個連通圖連線起

最小生成樹演算法【圖解】--一文帶你理解什麼是Prim演算法Kruskal演算法

假設以下情景,有一塊木板,板上釘上了一些釘子,這些釘子可以由一些細繩連線起來。假設每個釘子可以通過一根或者多根細繩連線起來,那麼一定存在這樣的情況,即用最少的細繩把所有釘子連線起來。 更為實際的情景是這樣的情況,在某地分佈著N個村莊,現在需要在N個村莊之間修路,每個村莊之前的距離不同,問怎麼修最短的路,將各個

第七章 圖(最小生成樹之prime演算法 kruskal演算法

最小生成樹 所謂最小生成樹,就是在一個具有N個頂點的帶權連通圖G中,如果存在某個子圖G’,其包含了圖G中的所有頂點和一部分邊,且不形成迴路,並且子圖G’的各邊權值之和最小,則稱G’為圖G的最小生成樹。 由定義我們可得知最小生成樹的

資料結構演算法題/圖的生成樹:Prim演算法Kruskal

1. 生成樹 在一個任意連通圖G中,如果取它的全部頂點和一部分邊構成一個子圖G',即:V(G')=V(G)和E(G')⊆E(G) 若同時滿足邊集E(G')中的所有邊既能夠使全部頂點連通而又不形成任何迴路,則稱子圖G'是原圖G的一棵生成樹。 連通圖是n個點n-1條邊。 在圖G的一

primKruskal演算法

prim演算法 1 #include <iostream> 2 #include <cstdio> 3 #define max 10 4 using namespace std; 5 typedef struct 6 { 7 int relat

Project-2: Prim Kruskal 演算法尋找最小生成樹

Prim 和 Kruskal 演算法尋找最小生成樹 實驗原理 堆 堆是一種經過排序的完全二叉樹,其中任一非終端節點的資料值均不大於(或不小於)其左子節點和右子節點的值。最大堆和最小堆是二叉堆的兩種形式。最大堆:根結點的鍵值是所有堆結點鍵值中最大者。最小堆: