prim演算法思想
㈠ 話說最小生成樹的prim演算法和kursual演算法的區別
prim演算法和kurskal演算法解決的問題是相同的,都用來求最小生成樹。從某一結點A出發,按照一定次序,經過中間結點集Q中的每一個結點,得到最短路徑,稱為最小生成樹。
kurskal演算法的核心思想就是「盡可能的選取短邊」,按照長度從小到大依次加入生成樹;prim演算法引入一個概念——生長點(和非生長點),每次加入的最短邊是與生長點相鄰的最短邊,初始狀態下,唯一的一個點就是生長點,隨著新邊的加入,每次加入的邊的末端就是生長點,若某一生長點已經沒有相鄰邊可以加入,就回溯到上一級結點,加入新邊,直到Q中的所有結點都加入圖中。
一般教材編的都很清楚的,結合我這個,再看看書,相信你很快就會明白的。
㈡ 什麼是Prim演算法
Prim演算法
Prim演算法用於求無向圖的最小生成樹
設圖G =(V,E),其生成樹的頂點集合為U。
①、把v0放入U。
②、在所有u∈U,v∈V-U的邊(u,v)∈E中找一條最小權值的邊,加入生成樹。
③、把②找到的邊的v加入U集合。如果U集合已有n個元素,則結束,否則繼續執行②。
其演算法的時間復雜度為O(n^2)
Prim演算法實現:
(1)集合:設置一個數組set[i](i=0,1,..,n-1),初始值為 0,代表對應頂點不在集合中(注意:頂點號與下標號差1)
(2)圖用鄰接陣表示,路徑不通用無窮大表示,在計算機中可用一個大整數代替。
參考程序
/* Prim.c
Copyright (c) 2002, 2006 by ctu_85
All Rights Reserved.
*/
/* The impact of the situation of articulation point exists can be omitted in Prim algorithm but not in Kruskal algorithm */
#include "stdio.h"
#define maxver 10
#define maxright 100
int main()
{
int G[maxver][maxver],in[maxver]=,path[maxver][2];
int i,j,k,min=maxright;
int v1,v2,num,temp,status=0,start=0;
restart:
printf("Please enter the number of vertex(s) in the graph:\n");
scanf("%d",&num);
if(num>maxver||num<0)
{
printf("Error!Please reinput!\n");
goto restart;
}
for(j=0;j<num;j++)
for(k=0;k<num;k++)
{
if(j==k)
G[j][k]=maxright;
else
if(j<k)
{
re:
printf("Please input the right between vertex %d and vertex %d,if no edge exists please input -1:\n",j+1,k+1);
scanf("%d",&temp);
if(temp>=maxright||temp<-1)
{
printf("Invalid input!\n");
goto re;
}
if(temp==-1)
temp=maxright;
G[j][k]=G[k][j]=temp;
}
}
for(j=0;j<num;j++)
{
status=0;
for(k=0;k<num;k++)
if(G[j][k]<maxright)
{
status=1;
break;
}
if(status==0)
break;
}
do
{
printf("Please enter the vertex where Prim algorithm starts:");
scanf("%d",&start);
}while(start<0||start>num);
in[start-1]=1;
for(i=0;i<num-1&&status;i++)
{
for(j=0;j<num;j++)
for(k=0;k<num;k++)
if(G[j][k]<min&&in[j]&&(!in[k]))
{
v1=j;
v2=k;
min=G[j][k];
}
if(!in[v2])
{
path[i][0]=v1;
path[i][1]=v2;
in[v1]=1;
in[v2]=1;
min=maxright;
}
}
if(!status)
printf("We cannot deal with it because the graph is not connected!\n");
else
{
for(i=0;i<num-1;i++)
printf("Path %d:vertex %d to vertex %d\n",i+1,path[i][0]+1,path[i][1]+1);
}
return 1;
}
Prim演算法。
設圖G =(V,E),其生成樹的頂點集合為U。
①、把v0放入U。
②、在所有u∈U,v∈V-U的邊(u,v)∈E中找一條最小權值的邊,加入生成樹。
③、把②找到的邊的v加入U集合。如果U集合已有n個元素,則結束,否則繼續執行②。
其演算法的時間復雜度為O(n^2)
參考程序
//Prim 演算法 讀入頂點數(n)、邊數(m),邊的起始點和權值 用鄰接矩陣儲存
//例如
//7 12 (7個頂點12條邊)
//1 2 2
//1 4 1
//1 3 4
//2 4 3
//2 5 10
//3 4 2
//4 5 7
//3 6 5
//4 6 8
//4 7 4
//5 7 6
//6 7 1
#include <stdio.h>
#include <string.h>
int main()
{
int m , n;
int a[201][201] , mark[201] , pre[201] , dist[201];
int s , t , w;
int i , j , k , min , tot;
freopen("Prim.txt" , "r" , stdin);
//讀入數據
memset(a , 0 , sizeof(a));
scanf("%d %d" , &n , &m);
for (i = 0; i < m; i ++)
{
scanf("%d %d %d" , &s , &t , &w);
a[s][t] = w; a[t][s] = w;
}
//賦初值
memset(mark , 0 , sizeof(mark));
memset(pre , 0 , sizeof(pre));
memset(dist , 9999 , sizeof(dist));
dist[1] = 0;
//Prim
for (i = 1; i <= n; i ++)
{
min = 9999; k = 0;
for (j = 1; j <= n; j ++)
if ((mark[j] == 0) && (dist[j] < min)) {min = dist[j]; k = j;}
if (k == 0) break;
mark[k] = 1;
for (j = 1; j <= n; j ++)
if ((mark[j] == 0) && (a[k][j] < dist[j]) && (a[k][j] > 0))
{
dist[j] = a[k][j];
pre[j] = k;
}
}
tot = 0;
for (i = 1; i <= n; i ++) tot += dist[i];
printf("%d\n" , tot);
return 0;
}
㈢ 最小生成樹
所謂最小生成樹,就是在一個具有N個頂點的帶權連通圖G中,如果存在某個子圖G',其包含了圖G中的所有頂點和一部分邊,且不形成迴路,並且子圖G'的各邊權值之和最小,則稱G'為圖G的最小生成樹。 由定義我們可得知最小生成樹的三個性質:
•最小生成樹不能有迴路。
•最小生成樹可能是一個,也可能是多個。
•最小生成樹邊的個數等於頂點的個數減一。宴昌 本文將介紹兩種最小生成樹的演算法,分別為克魯斯卡爾演算法(Kruskal Algorithm)和普利姆演算法(Prim Algorithm)。
克魯斯卡爾演算法的核心思想是:在帶權連通圖中,不斷地在邊集合中找到最小的邊,如果該邊滿足得到最小生成樹的條件,就將其構造,直到最後得到一顆最小生成樹。
克魯斯卡爾演算法的執行步驟:
第一步:在帶權連通圖中,將邊的權值排序;
第二步:判斷是否需要選擇這條邊(此時圖中的邊已按權值從小到大排好序)。判斷的依據是邊的兩個頂點是亂蘆否已連通,如果連通則繼續下一條;如果不連通,那麼就選擇晌陪扒使其連通。
第三步:循環第二步,直到圖中所有的頂點都在同一個連通分量中,即得到最小生成樹。
下面我用圖示法來演示克魯斯卡爾演算法的工作流程,如下圖:
㈣ 普里姆演算法是什麼
普里姆(Prim)演算法,和克魯斯卡爾演算法一樣,是用來求加權連通圖的最小生成樹的演算法。
普里姆演算法(Prim演算法),圖論中的一種演算法,可在加權連通圖里搜索最小生成樹。意即由此演算法搜索到的邊子集所構成的樹中,不但包括了連通圖里的所有頂點(英語:Vertex (graph theory)),且其所有邊的權值之和亦為最小。
該演算法於1930年由捷克數學家沃伊捷赫·亞爾尼克(英語:Vojtěch Jarník)發現;並在1957年由美國計算機科學家羅伯特·普里姆(英語:Robert C. Prim)獨立發現;1959年,艾茲格·迪科斯徹再次發現了該演算法。因此,在某些場合,普里姆演算法又被稱為DJP演算法、亞爾尼克演算法或普里姆-亞爾尼克演算法。
基本思想:
對於圖G而言,V是所有頂點的集合;現在,設置兩個新的集合U和T,其中U用於存放G的最小生成樹中的頂點,T存放G的最小生成樹中的邊。
從所有uЄU,vЄ(V-U) (V-U表示出去U的所有頂點)的邊中選取權值最小的邊(u, v),將頂點v加入集合U中,將邊(u, v)加入集合T中,如此不斷重復,直到U=V為止,最小生成樹構造完畢,這時集合T中包含了最小生成樹中的所有邊。
㈤ 鐢誨嚭綆楁硶鐨勬祦紼嬪浘
瀵逛簬榪欑嶆瘮杈冮珮綰х殑綆楁硶浠g爜鐩存帴鐪嬬▼搴忎細姣旇緝钂欙紝浣犲氨鍏夌湅鎴戠殑綆楁硶嫻佺▼鍚э紝prim綆楁硶鐢ㄧ殑鏄璐蹇冪畻娉曠殑鎬濇兂錛屽嵆姣忎竴姝ラ兘浣滃嚭灞閮ㄧ殑鏈浼樿В錛屽叧浜巔rim 綆楁硶涓轟粈涔堣兘鐢ㄨ椽蹇冪畻娉曠殑璇佹槑錛屼綘鍙浠ュ弬鑰冦婅$畻鏈虹畻娉曡捐′笌鍒嗘瀽銆嬭繖鏈涔︺傦紙鎴戝弽姝d笉鎯崇湅閭d箞鏃犺亰鐨勮瘉鏄庯紝涔熺湅涓嶆槑鐧斤紝鍛靛懙錛夈
瀹氫箟涓涓闆嗗悎v 鍜 a錛屽叾涓璿鏄鍏ㄤ綋鑺傜偣錛堟昏妭鐐規暟涓簄錛夌殑闆嗗悎錛寁鍒濆嬩負絀恆傚畾涔変竴涓璁板綍鏈灝忕敓鎴愭暟杈規暟鐨勫彉閲廲銆
1.鍦╲涓浠婚変竴涓鑺傜偣錛屽苟鍔犲叆鍒癮涓銆傚湪v涓鍒犻櫎璇ヨ妭鐐廣
2.閫変竴涓鍦ㄦ墍鏈夎繛鎺v闆嗗悎鍜宎闆嗗悎鏉冨兼渶灝忕殑杈癸紙鍗充竴涓鑺傜偣鏄痸鐨勬煇涓涓鑺傜偣錛屼竴涓鏄痑涓鐨勬煇涓涓鑺傜偣錛
3銆傚皢涓や釜鑺傜偣榪炴帴銆傚皢c鍔1
4.灝嗙3姝ユ墠鍦╲涓鑺傜偣鍒犻櫎騫跺姞鍏ュ埌a涓.
5.濡傛灉c涓簄-1鍒欏畬鎴愭渶灝忕敓鎴愭爲錛屽惁鍒欏洖鍒扮2姝ャ
鏄庣櫧浜嗘病錛熶笉鏄庣櫧鍐嶉棶鎴戝晩錛屽笇鏈涘逛綘鏈夋墍甯鍔┿