日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【算法】prim算法(最小生成树)(与Dijkstra算法的比较)

發(fā)布時(shí)間:2024/4/19 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【算法】prim算法(最小生成树)(与Dijkstra算法的比较) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最小生成樹(shù):

生成樹(shù)的定義:給定一個(gè)無(wú)向圖,如果它的某個(gè)子圖中任意兩個(gè)頂點(diǎn)都互相連通并且是一棵樹(shù),那么這棵樹(shù)就叫做生成樹(shù)。(Spanning Tree)

最小生成樹(shù)的定義:在生成樹(shù)的基礎(chǔ)上,如果邊上有權(quán)值,那么使得邊權(quán)和最小的生成樹(shù)叫做最小生成樹(shù)。(Minimum Spanning Tree )

解決生成樹(shù)有兩種常用的算法:Kruskal算法和prim算法。

這里我們講的是prim算法求生成樹(shù)的解法。

算法思想:

ans = 0;(表示權(quán)值和)

1.在無(wú)向圖的基礎(chǔ)上,想象我們有一個(gè)點(diǎn)的集合X(初始狀態(tài)為空)。

2.在集合X中加入一個(gè)初始點(diǎn)x,用這個(gè)初始點(diǎn)更新其他點(diǎn)離集合X的距離mincost[ ],標(biāo)記初始點(diǎn)為使用過(guò)(使用過(guò):加入集合X)。

3.找一個(gè)未使用過(guò)(集合X外的點(diǎn))的離集合X最小距離最小的點(diǎn),找到了這樣一個(gè)點(diǎn),將這個(gè)點(diǎn)加入集合X,ans += 這個(gè)與集合X的距離,

用這個(gè)新加入的點(diǎn)更新其他點(diǎn)離集合X的最小距離mincost[ ],標(biāo)記新加入的點(diǎn)為使用過(guò),繼續(xù)執(zhí)行第3步;找不到這樣一個(gè)點(diǎn),則進(jìn)入第4步。

4.輸出ans。

mincost[i] 表示點(diǎn)i離集合X的最小距離。(離集合X中所有點(diǎn)中最近的點(diǎn)的距離)

簡(jiǎn)單來(lái)說(shuō)就是:

想象一下,有10張面額不同的毛爺爺在你面前,每次只能拿1張,只能拿5次,你肯定會(huì)每次都拿這n張(n<=10)中最大的那張,

這樣拿5次,讓總額最大。這個(gè)算法也是同樣的道理,不斷的加入可觸及的最近的點(diǎn),最后權(quán)值一定是最小的。

額,當(dāng)然10張不同的毛爺爺是不存在的。所以一分都拿不到,還是看代碼吧:

代碼:

#include <bits\stdc++.h> using namespace std; #define INF 2147483647 #define MAX_V 1000 #define MAX_E 2000 int cost[MAX_V][MAX_V]; // cost[i][j] 表示頂點(diǎn)i到頂點(diǎn)j的權(quán)值,不存在時(shí)為INF int mincost[MAX_V]; // mincost[i] 表示i點(diǎn)與集合X的最小距離 bool used[MAX_V]; // used[i]表示點(diǎn)i是否在集合中 int V; //頂點(diǎn)數(shù) //表示從點(diǎn)x產(chǎn)生的最小生成樹(shù),這么考慮是因?yàn)檎麄€(gè)圖可能不連通 int prim(int x){//最初X集合為空,每個(gè)點(diǎn)到集合X的最小距離都是INF for(int i = 0;i < V; ++i){mincost[i] = INF;used[i] = false;}//將點(diǎn)x與集合X的距離置為0,第一次集合X會(huì)加入點(diǎn)x mincost[x] = 0;int res = 0;while(true){int v = -1;//找到離集合X最近的點(diǎn),第一次加入點(diǎn)x for(int u = 0;u < V; ++u){if(!used[u] && (v == -1 || mincost[u] < mincost[v])) v = u;}//如果所有點(diǎn)可達(dá)的點(diǎn)都加入集合X中了,就跳出 if(v == -1) break;used[v] = true;res += mincost[v];mincost[v] = 0; //把點(diǎn)v加入到集合X中,這一步幫助理解,可寫可不寫 ,因?yàn)閏ost[v][v] = 0 //用新加入的點(diǎn)v更新其他點(diǎn)離與集合X的最小距離 for(int u = 0;u < V; ++u){mincost[u] = min(mincost[u] , cost[v][u]);}}return res; }int main(){ }

與Dijkstra算法的比較

Prim算法與Dijkstra算法都是從某個(gè)點(diǎn)出發(fā),不斷加入最近的點(diǎn)。最終都要把所有可以加的點(diǎn)加完。

Prim算法是求最小生成樹(shù),Dijkstra是求單源最短路徑。

來(lái)個(gè)Dijkstra求單源最短路徑的代碼,與Prim算法比較一下:

#include <bits\stdc++.h> using namespace std; #define INF 2147483647 #define MAX_V 1000 #define MAX_E 2000 //單源最短路徑問(wèn)題(Dijkstra算法) int cost[MAX_V][MAX_V]; //cost[u][v]表示e = (u,v)的權(quán)值 int d[MAX_V]; //頂點(diǎn)s出發(fā)的最短距離 //不同處1 bool used[MAX_V]; //標(biāo)記使用過(guò)的點(diǎn) int V; //頂點(diǎn)數(shù) void dijkstra(int s){fill(d, d+V, INF);fill(used, used + V, INF);d[s] = 0;while(true){int v = -1;//找到一個(gè)距離最近的沒(méi)有使用過(guò)的點(diǎn) for(int u = 0;u < V; u++){if(!used[u] && (v == -1 || d[u] < d[v])) v = u;}//如果所有的點(diǎn)都被使用過(guò)了,則breakif(v == -1) break;//標(biāo)記當(dāng)前點(diǎn)被使用過(guò)了 used[v] = true;//更新這個(gè)找到的距離最小的點(diǎn)所連的點(diǎn)的距離 for(int u = 0;u < V; u++){d[u] = min(d[u], d[v] + cost[v][u]); //不同處2}} }int main(){ }

我們可以看到代碼基本上是一樣的,只有

不同處1:Djikstra中用d[i]表示i點(diǎn)離源點(diǎn)的最短距離,Prim中用mincost[i] 表示i點(diǎn)與集合X的距離。

不同處2:Djikstra中更新d[u] = min( d[u] , d[v] + cost[v][u] ); 用新加入的點(diǎn)更新其他點(diǎn)與源點(diǎn)的最小距離。

Prim中更新mincost[u] = min( mincost[u] , cost[v][u] ); 用新加入的點(diǎn)更新點(diǎn)i與集合X的最小距離。

我認(rèn)為只用加幾行代碼,無(wú)論是在prim中加,還是在Dijkstra中加,就既可以求單源最短路徑,又可以求最小生成樹(shù)了。

總結(jié)

以上是生活随笔為你收集整理的【算法】prim算法(最小生成树)(与Dijkstra算法的比较)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。