最小生成樹一 Prim演算法

2021-10-25 17:47:57 字數 2836 閱讀 6759

描述

小ho也是一路看著小hi玩這個遊戲過來的,於是便提出了自己的想法:「為什麼一定要最少花費呢?隨便造造能過關不就行了!」

小hi怒道:「強迫症你知道什麼意思麼?」

於是小ho閉嘴不敢言。

小hi哼了一聲,接著道:「也好,趁此機會,我可以教教你最小生成樹是什麼一回事——先說這個名字的由來,生成樹這個名詞是相對於乙個確定的圖g來的,也就是說你不能說一棵樹t是生成樹,只能說t是g的生成樹,而生成樹的意思就是,t的結點與g的結點是一樣的,而且t的邊集是g的邊集的子集,這就是所謂的生成樹。而最小生成樹——意思就是g的所有生成樹中邊權和最小的一棵。」

「那麼最小生成樹可以有不止一棵吧?」小ho問道。

小hi點頭答道:「是的,所以這個問題只需要輸出最小生成樹的邊權和就可以了——這肯定是唯一的。」

小ho撓了撓頭,道:「那到底該怎麼做呢?我一點頭緒都沒有——如果使用列舉的方式那時間複雜度是指數級別的,肯定做不出來!」

「且聽我慢慢道來!」小hi道:「首先我想證明乙個結論:對於城市i(i≠1),如果i與城市1的距離不超過其他任何城市j(j≠1)與城市1的距離,那麼(1, i)這一條邊一定存在於某一棵最小生成樹中。」

「你的意思是從城市1出發的最短的邊一定屬於某棵最小生成樹?聽上去有點道理,但是為什麼啊?」小ho問道。

小hi點了點頭:「證明是這樣的:對於一棵最小生成樹t——如果(1, i)在其中,那麼該結論就已經得到了證明,所以我們考慮的是(1, i)不在其中的情況。而1和i之間肯定會通過某條路徑連通(因為是樹不是森林),不妨假設為1-p1-p2-…-pk-i。」

「嗯嗯,然後呢?」

「那麼,如果我將(1, p1)這條邊刪去,新增上(1, i)這條邊,那麼這還是一棵生成樹麼?」小hi問道。

「點沒有發生變化,邊集仍然是圖g的子集,那麼只需要看還是不是乙個棵樹了——所有點之間仍然連通,而且沒有環(新增邊(1, i)後僅有乙個環1-p1-p2-…-pk-i-1,但是(1, p1)卻被刪去了)!所以這還是一棵樹,也就是說……這樣改動之後仍然是一棵生成樹。」小ho想了想,說道。

「如果我們稱改動後的生成樹為t』的話,不難發現,由於(1, p1)的費用大於等於(1, i)的費用,我們可以知道t』的邊權和小於等於t,又因為t本身已經是最小生成樹了,不難發現t』也會是最小生成樹……」小ho恍然大呼:「也就是說結論得到了證明:(1, i)這一條邊一定存在於某一棵最小生成樹中。」

「對的!所以萬里長征第一步已經走完了,接下來只需要按照第一步走下去就行了!」小hi道。

「什麼意思……接下來的情況要複雜很多吧?」小ho困惑了。

小hi嘆了口氣道:「笨……你這麼想,如果我確定了(1, i)這條邊一定存在於某一棵最小生成樹中,那麼我仿照dijstra演算法的思想,將1和i合併為乙個點,那麼問題是不是就變成了求剩下的n-2個點和這個點的最小生成樹?問題沒有變化,但是規模卻縮小了,那麼就只需要一次一次的進行這樣的步驟,這個問題不是就能夠完美的解決了麼?」

小ho邊思索邊道:「也就是說……對於乙個n個點的最小生成樹問題,我求出與1號點最近的點i,將這兩個點合併,剩下n-1個點,然後求與新的1號點最近的點i』,將這兩個點合併,剩下了n-2個點……然後依次類推,直到最後剩下乙個點的時候,再將之前所有合併的邊的費用加起來——就是答案了!」

「孺子可教也,趕緊去把程式寫了!我一會要用呢!」

輸入每個測試點(輸入檔案)有且僅有一組測試資料。

在一組測試資料中:

第1行為1個整數n,表示小hi擁有的城市數量。

接下來的n行,為乙個n*n的矩陣a,描述任意兩座城市之間建造道路所需要的費用,其中第i行第j個數為aij,表示第i座城市和第j座城市之間建造道路所需要的費用。

對於100%的資料,滿足n<=10^3,對於任意i,滿足aii=0,對於任意i, j滿足aij=aji, 0對於每組測試資料,輸出1個整數ans,表示為了使任意兩座城市都可以通過所建造的道路互相到達至少需要的建造費用。

sample input

5

0 1005 6963 392 1182

1005 0 1599 4213 1451

6963 1599 0 9780 2789

392 4213 9780 0 5236

1182 1451 2789 5236 0

sample output

4178
#include

int map[

1010][

1010];

intmain()

, dis[

1010];

int n, i, j, k, t;

scanf

("%d"

,&n)

;for

(i=1

;i<=n; i++

)for

(j=1

; j<=n; j++

)scanf

("%d"

,&map[i]

[j])

;int count =

1, sum=0;

for(i=

1; i<=n; i++

) dis[i]

=map[1]

[i];

//先讓dis陣列表示從原點到各個點的距離

book[1]

=1;while

(count//當還有點未加入生成樹時

} book[t]=1

, count++

, sum+

=dis[t]

;//標記並記錄此點,計算距離

for(k=

1; k<=n; k++)}

printf

("%d"

,sum)

;return0;

}

最小生成樹一Prim演算法

題目一堆廢話,直接看輸入輸出 輸入在一組測試資料中 第1行為1個整數n,表示小hi擁有的城市數量。接下來的n行,為乙個n n的矩陣a,描述任意兩座城市之間建造道路所需要的費用,其中第i行第j個數為aij,表示第i座城市和第j座城市之間建造道路所需要的費用。n 10 3 輸出對於每組測試資料,輸出1個...

最小生成樹(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...