最小生成樹一 Prim演算法 (模板題)

2021-08-21 21:13:10 字數 2654 閱讀 8228

描述

但是,問題也接踵而來——小hi現在手上擁有n座城市,且已知這n座城市中任意兩座城市之間建造道路所需要的費用,小hi希望知道,最少花費多少就可以使得任意兩座城市都可以通過所建造的道路互相到達(假設有a、b、c三座城市,只需要在ab之間和bc之間建造道路,那麼ac之間也是可以通過這兩條道路連通的)。

小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
最小生成樹prim的模板題。

**:

#include#include#define inf 99999999

int map[1010][1010],dis[1010],book[1010];

int main()

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

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

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

} return 0;

}

最小生成樹 Prim演算法(模板)

基本演算法 首先以乙個結點作為最小生成樹的初始結點,然後以迭代的方式找出與最小生成樹中各結點權重最小邊,並加入到最小生成樹中。選擇一條權值最小,且一端點a已加入生成樹,另一端點b在剩餘結點集內的邊作為最小生成樹上的邊,同時將b列入生成樹的已有點集中。當所有結點都加入到最小生成樹中之後,就找出了連通圖...

最小生成樹prim演算法模板

include using namespace std const int inf 0x3f3f3f3f 最大值,方便計算 int n,m n是點的個數,m是邊的數量 int dis 105 vis 105 dis是判斷未加入生成樹的頂點到已知生成樹的最短距離,vis判斷是否已經加入生成樹 int ...

模板) 最小生成樹Prim演算法

演算法跟dijkstra很像 但是要特別注意兩點 1.最好使用乙個額外的陣列來保證每個點只被訪問一次,否則的話應該保證在35行處使用e.dis dis e.num 而不僅是 否則會造成一些相等的額外相加。2.40行的地方要注意與dijkstra的區別!不是加而是直接換!include include...