今天覆習最小生成樹演算法。
最小生成樹指的是在乙個圖中選擇n-1條邊將所有n個頂點連起來,且n-1條邊的權值之和最小。形象一點說就是找出一條路線遍歷完所有點,不能形成迴路且總路程最短。
kurskal演算法的核心思想是將邊按權值排序,每次選出權值最小的邊,只要不會形成迴路就加入結果集,如果形成了迴路就不選這條邊,類似於貪心的思想。
具體做法是先將邊按權值公升序排序然後依次遍歷,判斷是否形成迴路的方法是將點劃分不同集合,初始狀態每個點為乙個集合,只有當一條邊的兩端分別位於兩個集合時才選擇這條邊,否則就丟棄,這裡用到了並查集來處理集合關係,可以參考這篇博文:選擇一條邊之後要將兩個點合併到同一集合。
模板題:
**如下,還是比較好理解的,時間複雜度為\(o(mlogm)\)。
#include #include using namespace std;
int n, m;
int pre[5005];
int find(int x)
struct line
}arr[200005];
int kruskal()
} return cnt == 1 ? res : -1;//如果cnt不等於1說明沒找到n-1條邊,無最小生成樹
}int main()
kruskal演算法是選擇邊的思路,而prim演算法通過選擇點來得到最小生成樹,有點類似於dijkstra的感覺,初始源點可以任意選擇,把點劃分成已選擇的點和未選擇的點兩個集合,需要維護乙個dis陣列代表每個點到已選擇點的最短距離,不斷把dis最小的未選擇點加入已選擇點集合然後更新dis,當所有點都變成已選擇點(dis==0)的時候就得到了最小生成樹。
**如下,真的是跟dijkstra很像了。
#include #include using namespace std;
#define inf 2000000000
int n, m;
int dis[5005];
int total = 0;
int head[5005], val[400005], to[400005], nextl[400005];
void addline(int a, int b, int c)
int prim()
} if (min == inf && u != 1)return -1;//如果遍歷之後未選擇點dis都為inf,說明該圖是非連通圖
res += dis[u];
dis[u] = 0;
for (int j = head[u]; j; j = nextl[j])//更新該點周圍的dis
}return res;
}int main()
int res = prim();
if (-1 == res)cout << "orz"; else cout << res;
return 0;
}
既然prim也是要每次取dis最小的點,當然也和dijkstra一樣可以用堆優化,樸素的prim時間複雜度為\(o(n^2)\),優化後達到\(o(nlogn)\),**如下:
#include #include #include using namespace std;
#define inf 2000000000
int n, m;
int dis[5005];
int total = 0;
int head[5005], val[400005], to[400005], nextl[400005];
bool mark[5005];
void addline(int a, int b, int c)
typedef pairp;
priority_queue, greater> q;
int prim()
} }return res;
}int main()
int res = prim();
if (-1 == res)cout << "orz"; else cout << res;
return 0;
}
所以選擇使用哪個演算法就看是點多還是邊多了。 最小生成樹演算法 Prim演算法和Kruskal演算法
prim演算法理解,可以看這篇文章 其實就是每次從當前樹中外選取乙個離樹最近且不構成環的點,同時sum記錄權值,然後把這個點加入樹中,直到所有節點都被訪問過,最小生成樹生成成功,輸出最小生成樹的權值和。下面是prim演算法的板子,和最短路有點相似,也稱為 加點法 最小生成樹prim演算法 inclu...
最小生成樹演算法總結
首先,最小生成樹是建立在無向圖中的,對於乙個有n個點的圖,最少需要n 1條邊使得這n個點進行連通,由這n 1條邊組成的子圖稱為原圖的生成樹,乙個圖的生成樹並不是唯一的。最小生成樹則是樹中權值之和最小的一顆生成樹,最小生成樹也可能不唯一。最小生成樹一般有兩種演算法,一種是prim演算法,另一種是kru...
soj 3366 複習最小生成樹kruskal
題目大意 要建井,每個地方都要有,可以選擇直接在這裡挖井,也可以選擇從其他地方已經有井的地方建一條路到這個地方來。有一段時間沒有寫過最小生成樹了,感覺都有一點快要忘記了的感覺。這道題之前沒有過,借鑑了一下別人的思想。發現真的好簡單。而且這種方法在以前使用過,這回居然沒有想出來,要反思一下了。感覺跟之...