最小生成樹之Prime演算法(臨接表 優先佇列實現)

2021-09-23 10:45:48 字數 4608 閱讀 4280

鄰接表,一種存圖的方式,用到了c++裡面的stl標準模板庫裡面的vector,vector是一種不定長陣列。

#include標頭檔案

vectorv;定義乙個int型的動態陣列;

但鄰接表用到的vector的資料型別是node型別的結構體;

struct node

};//鄰接表

vectorv[n];//定義v個鍊錶;

【鄰接表的存圖思想】:對每個頂點,使用不定長的鍊錶(用vector來實現)來儲存從該點出發的所有邊的情況,第 i 個鍊錶的第 j 個值就是頂點 i 到頂點 j 的權值。

prime演算法用來解決最小生成樹的問題,我們可以想到,它的邊的權值是必須從小到大排序的,而優先佇列的預設從大到小排序。所以,我們得寫乙個自定義排序,並且這裡的優先佇列的資料型別不是int型,而是node結構體型別。

struct node

};//鄰接表

struct cmp

};priority_queue, cmp> pq;//公升序的優先佇列;

和普通的prime演算法一樣,這個演算法也需要用到兩個陣列,乙個用來記錄到最小生成樹的距離。乙個用了記錄已訪問的結點;

先對這兩個陣列進行初始化:將標記陣列全部初始化為0,表示全部為訪問;將距離陣列初始化為無窮大,表示任意兩個結點不聯通;

int dis[n];//記錄到生成樹的最小距離

int vis[n];//標記陣列

memset(dis, inf, sizeof(dis));//初始化;

memset(vis, 0, sizeof(vis));

以下是用鄰接表+優先佇列實現prime演算法的難點,我也是剛搞懂,下面只是我的理解,可能有不對的地方;(1)

dis[x] = 0;
[x]表示以任意乙個結點開始,即:最小生成樹的根節點擊取是任意的,我這裡選的是0,即:dis[0] = 0;,從0號結點開始構建最小生成樹;

(2)

pq.push(node(x, 0));
這裡的x和上面的x一樣,表示將到達x的結點壓入佇列。因為剛開始沒有結點,它是第乙個結點,所以到它的權值是0;

(3)

dis[0] = 0;

pq.push(node(0, 0));

while(pq.empty() != 1)

vis[p] = 1;//將它到達的結點標記;

for (i = 0; i < n; i++)}}

彈出此時的佇列中的隊首元素(它是乙個結點)並刪除,如果這個隊首元素要達到的結點已經被訪問過,終止此次迴圈,進入下一次迴圈。如果這個隊首元素要達到的結點沒有被訪問過,則進行以下操作:

標記它要達到的結點,然後定義乙個臨時的結構體變數代替操作,如果它要達到的結點沒有被訪問過且它要到達的結點到最小生成樹的距離大於它自己到最小生成樹的距離,就對dis距離陣列進行更新;dis[x.to] = x.v;,並且將這個結點壓入佇列;pq.push(node(x.to, dis[x.to]));

注意:v[p][i]表示p點指向i點。。。。(好像可以認為它是乙個結點)

注意:這裡的每個結點包括兩個資訊:1是它要指向的點;2是它到指向的點的權值;

最後,對dis陣列求和,就是最小生成樹的值;

完整**如下:

#include

#include

#include

#include

using namespace std;

#define inf 0x3f3f3f3f

#define n 1000

int dis[n]

;//記錄到生成樹的最小距離

int vis[n]

;//標記陣列

struct node};

//鄰接表

struct cmp};

vector v[n]

;//定義v個鍊錶;

intprime

(int n)

vis[p]=1

;//將它到達的結點標記;

for(i =

0; i < n; i++)}

}int sum =0;

for(i =

0; i < n; i++

)return sum;

}int

main()

for(i =

0; i < n; i++)}

int k =

prime

(n);

cout << k << endl;

return0;

}

注意:要對不定長陣列v進行清空操作:

for (i = 0; i < n; i++)//對鍊錶進行清空操作;

例如,這樣一幅圖:它四個結點,分別是:

為了便於理解,我們看下面的**:

#include

#include

#include

#include

using namespace std;

const

int maxn =

1000

;const

int inf =

0x3f3f3f3f

;int d[maxn]

;//距離向量

int vis[maxn]

;//標記陣列

int sum;

struct node};

struct cmp};

vector v[maxn]

;void

prim

(int n)

vis[pos]=1

;for

(i =

0; i < n;i++)}

cout <<

"距離陣列d的值:"

;for

(i =

0; i < n; i++

) cout << endl;

} sum =0;

for(i =

0; i < n; i++)}

intmain()

for(i =

0; i < n; i++)}

prim

(n);

cout <<

"最小生成樹的值:"

; cout << sum << endl;

return0;

}

輸入:

4

0 4 9 21

4 0 8 17

9 8 0 16

21 17 16 0

輸出:

4

0 4 9 21

4 0 8 17

9 8 0 16

21 17 16 0

佇列大小:1

執行刪除操作之後的佇列大小:0

起點:0 終點:0: 權值:0

起點:0 終點:1: 權值:4

起點:0 終點:2: 權值:9

起點:0 終點:3: 權值:21

距離陣列d的值:0 4 9 21

佇列大小:3

執行刪除操作之後的佇列大小:2

起點:1 終點:0: 權值:4

起點:1 終點:1: 權值:0

起點:1 終點:2: 權值:8

起點:1 終點:3: 權值:17

距離陣列d的值:0 4 8 17

佇列大小:4

執行刪除操作之後的佇列大小:3

起點:2 終點:0: 權值:9

起點:2 終點:1: 權值:8

起點:2 終點:2: 權值:0

起點:2 終點:3: 權值:16

距離陣列d的值:0 4 8 16

佇列大小:4

執行刪除操作之後的佇列大小:3

佇列大小:3

執行刪除操作之後的佇列大小:2

起點:3 終點:0: 權值:21

起點:3 終點:1: 權值:17

起點:3 終點:2: 權值:16

起點:3 終點:3: 權值:0

距離陣列d的值:0 4 8 16

佇列大小:2

執行刪除操作之後的佇列大小:1

佇列大小:1

執行刪除操作之後的佇列大小:0

最小生成樹的值:28

最小生成樹之prime演算法

在這裡我就不擺最小生成樹的定義了,對於最小生成樹,我們必須注意一下兩點 1 盡可能選取權值小的邊,但不能構成迴路。2 選取合適的n 1條邊將聯通圖的n個頂點連線起來。演算法簡單描述 1 輸入 乙個帶權連通圖,其中頂點集合為v,邊集合為e 2 初始化 vnew 其中x為集合v中的任一節點 起始點 en...

最小生成樹 Prime演算法

對於乙個圖,它的所有生成樹中必有乙個 邊的權值最小 的生成樹,我們把它稱為最小生成樹。概念很抽象,換做實際問題 有十個城市,各個城市之間距離或遠或近。需要建設乙個道路網,把十個城市連線在一起,要求道路網的道路長度最小。各個城市的連線可以抽象為乙個圖,本質上即是求該圖的乙個最小生成樹。每乙個圖可能有多...

最小生成樹 prime演算法

問題 c 建立通訊 時間限制 1 sec 記憶體限制 128 mb 提交 7 解決 4 提交 狀態 討論版 題目描述 據不完全統計,受 影響,四川大部分災區通訊陷入癱瘓,數千個基站因斷電 傳輸中斷等原因退出服務,目前總公司已緊急部署對受災地區進行通訊搶修。按照應急通訊保障預案,必須盡快 付出代價最小...