再談最小生成樹(Prim演算法)

2021-08-16 01:12:39 字數 3369 閱讀 9907

prim演算法用最小堆,圖的鄰接矩陣儲存法,實現。

時間複雜度大大優化,按照鄙人的理解,其原理大概是用圖的鄰接矩陣儲存法儲存圖,然後建立乙個最小堆,先弄乙個最小生成樹,剛開始只有乙個元素,即1號元素,最小堆的頂部元素到最小生成樹的距離即為最小堆到最小生成樹的最小距離,然後取出最頂部元素,將最頂部元素放入最小生成樹中,並且以最頂部元素為踏板算出其他頂點(非樹頂點)到最小生成樹的距離(類似於dijkstra演算法)並進行鬆弛,並將最小堆恢復,並依次迴圈往復,直到算出n-1條邊為止。

下面符兩份**(乙個是prim演算法不借助堆和鄰接表,另乙個借助堆和鄰接表,第乙個時間複雜度高)

第一種:

#include 

int main()

,dis[7];

int inf=999999;

int cnt=0,sum=0;

scanf("%d%d",&n,&m);

//初始化

for(int i=1;i<=n;i++)

for(int j=1;j<=n;j++)

if(i==j)

e[i][j]=0;

else

e[i][j]=inf;

for(int i=0;iscanf("%d%d%d",&t1,&t2,&t3);

e[t1][t2]=t3;

e[t2][t1]=t3;

}for(int i=1;i<=n;i++)

dis[i]=e[1][i];

//prim核心部分

//將一號頂點加入生成樹

int i,j,k;

book[1]=1;

cnt++;

while(cntfor(i=1;i<=n;i++)

if(book[i]==0&&dis[i]1;

sum+=dis[j];

cnt++;

//掃瞄當前定點j所有的邊,在以j為中間點,更新生成樹到每乙個非樹頂點的距離。

for(k=1;k<=n;k++)

if(book[k]==0&&dis[k]>e[j][k])

dis[k]=e[j][k];

}printf("%d\n",sum);

return

0; }

第二種:

上面這種方法時間複雜度為o(n^2),如果借助「堆」,每次選邊的時間複雜度為o(logm),然後使用鄰接表來儲存圖,整個演算法的時間複雜度降低為o(mlogn),使用堆優化,需要使用三個陣列,陣列dis用來記錄生成樹到個個頂點的距離,陣列h是乙個最小堆,堆裡面儲存的是頂點編號,但這裡並不是按照頂點編號來建立最小堆的,而是按照頂點在陣列dis中的值來建立最小堆的,此外還需要用乙個陣列pos來記錄每個頂點在最小堆中的位置。

**如下

#include 

#include

int dis[7],book[7];

int size,h[7],pos[7];

//交換函式,用來交換堆中兩個元素的值

void swap(int

x,int

y)//向下調整,用於初始化堆。

void siftdown(int i)

else

flag=1;

}return;

}//向上調整,用於鬆弛之後

void siftup(int i)

return;

}int

pop()

int main()

//開始使用鄰接表儲存邊;

for(i=1;i<=n;i++) first[i]=-1;

for(i=1;i<=2

*m;i++)

//prim核心;

//將1號頂點加入生成樹

book[1]=1;

cnt++;

//初始化dis陣列,這裡是各頂點到1號頂點的距離

dis[1]=0;

for(i=2;i<=n;i++) dis[i]=inf;

k=first[1];

while(k!=-1)

//初始化堆

size=n;

for(i=1;i<=size;i++)

for(i=size/2;i>=1;i--)

siftdown(i);

pop();//彈出乙個堆頂元素,因為此時堆頂元素是1;

while(cntpop();

book[j]=1;cnt++;sum+=dis[j];

//掃瞄當前j的所有邊,再以j為中間節點,進行鬆弛。

k=first[j];

while(k!=-1)

k=next[k];}}

printf("%d\n",sum);

return

0;}

/*

6 92 4 11

3 5 13

4 6 3

5 6 4

2 3 6

4 5 7

1 2 1

3 4 9

1 3 2

*/

kruskal演算法是一步一步將森林中的樹進行合併,而prim演算法則是通過每次增加一條邊來建立一棵樹。

kruskal演算法更適用於稀疏圖,沒有使用堆優化的prim演算法使用於稠密圖,而使用堆優化後更加適用於稠密圖。

prim(鄰接矩陣+堆)

using namespace std;

//#define debug

const int n=510;

int mmp[n][n];

int size;

int h[n],pos[n];

int dis[n];

bool vis[n];

inline void myswap(int

x,int

y)void siftdown(int i)else flag=1;

}}void siftup(int i)

}int

pop()

int main()

}for(int i=1;i<=n;i++)

//初始化堆

size=n;

for(int i=1;i<=size;i++)

for(int i=size/2;i>=1;i--)

mm(vis,0);

vis[1]=1;

int cnt=1,sum=0;

pop();

while(cntint j=pop();

vis[j]=1;cnt++;sum+=dis[j];

for(int i=1;i<=n;i++)}}

printf("%d\n",sum);

}return

0;}

最小生成樹(prim演算法)

最小生成樹是資料結構中圖的一種重要應用,它的要求是從乙個帶權無向完全圖中選擇n 1條邊並使這個圖仍然連通 也即得到了一棵生成樹 同時還要考慮使樹的權最小。prim演算法要點 設圖g v,e 其生成樹的頂點集合為u。把v0放入u。在所有u u,v v u的邊 u,v e中找一條最小權值的邊,加入生成樹...

最小生成樹 Prim演算法

prim 演算法 以領接矩陣儲存 圖g bool b i 表示頂點i是否被訪問,初始化時候memset b,false,sizeof b b 0 value,表示從第0個節點開始。用value i 表示節點i到最小生成樹a中定點的最小距離。例如value 1 a 0 1 int sum記錄權值和 i...

最小生成樹 prim 演算法

一 演算法描述 假設存在連通帶權圖g v,e 其中最小生成樹為t,首先從圖中隨意選擇一點s屬於v作為起始點,並將其標記後加入集合u 中。然後演算法重複執行操作為在所有v屬於u,u屬於v u的邊 v0,u0 屬於e中找一條代價最小的邊並加入集合t,同時將u0併入u,直到u v為止。這是,t中必有n 1...