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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法第四版- 4.3

發布時間:2023/12/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法第四版- 4.3 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

算法第四版- 4.3

最小生成樹MST

文章目錄

    • **算法第四版- 4.3**
  • 0.序
  • 1.Prim算法
  • 2. Kruskal算法

0.序

Prim算法,以頂點為單元,與圖中邊數無關,比較適合于稠密圖
Kruskal算法,以邊為頂點,時間主要取決于邊數,適合稀疏圖
下面代碼的來源
采用的是曼哈頓距離。

1.Prim算法

class Solution { public:int prim(vector<vector<int> >& points, int start) {int n = points.size();int res = 0;// 1. 將points轉化成鄰接矩陣, 這一步可有可無vector<vector<int> > g(n, vector<int>(n));for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {int dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]);g[i][j] = dist;g[j][i] = dist;}}// 記錄V[i]到Vnew的最近距離vector<int> lowcost(n, INT_MAX);// 記錄V[i]是否加入到了Vnewvector<int> v(n, -1);// 2. 先將start加入到Vnewv[start] = 0;for (int i = 0; i < n; i++) {if (i == start) continue;lowcost[i] = g[i][start];}// 3. 剩余n - 1個節點未加入到Vnew,遍歷for (int i = 1; i < n; i++) {// 找出此時V中,離Vnew最近的點int minIdx = -1;int minVal = INT_MAX;for (int j = 0; j < n; j++) {if (v[j] == 0) continue;if (lowcost[j] < minVal) {minIdx = j;minVal = lowcost[j];}}// 將該點加入Vnew,更新lowcost和vres += minVal;v[minIdx] = 0;lowcost[minIdx] = -1;// 更新集合V中所有點的lowcostfor (int j = 0; j < n; j++) {if (v[j] == -1 && g[j][minIdx] < lowcost[j]) {lowcost[j] = g[j][minIdx];}}}return res;}int minCostConnectPoints(vector<vector<int>>& points) {return prim(points,0);} };

樓上是O(n^2)
再補充一個堆優化的,O(mlogn),m為邊的數目

class Solution { public:int prim(vector<vector<int> >& points, int start) {int n = points.size();if (n == 0) return 0;int res = 0;// 將points轉化成鄰接表vector<vector<int> > g(n);for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {if (i == j) continue;g[i].push_back(j);g[j].push_back(i);}}// 記錄V[i]到Vnew的最近距離vector<int> lowcost(n, INT_MAX);// 記錄V[i]是否加入到了Vnewvector<int> v(n, -1);// 格式:<距離, 下標>priority_queue<pair<int, int>, vector<pair<int, int> >, greater<> > pq;pq.push(make_pair(0, start));while (!pq.empty()) {auto [dist, i] = pq.top();pq.pop();if (v[i] == 0) continue;v[i] = 0;res += dist;for (int k = 0; k < g[i].size(); k++) {int j = g[i][k];int w = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]);if (v[j] == -1 && lowcost[j] > w) {lowcost[j] = w;pq.push(make_pair(w, j));}}}return res;}int minCostConnectPoints(vector<vector<int>>& points) {return prim(points, 0); } };

2. Kruskal算法

依次選擇最小的邊,看是否形成環
時間復雜度O(m log(m) + m α(m) )

class Djset { public:vector<int> parent; // 記錄節點的根vector<int> rank; // 記錄根節點的深度(用于優化)vector<int> size; // 記錄每個連通分量的節點個數vector<int> len; // 記錄每個連通分量里的所有邊長度int num; // 記錄節點個數Djset(int n): parent(n), rank(n), len(n, 0), size(n, 1), num(n) {for (int i = 0; i < n; i++) {parent[i] = i;}}int find(int x) {// 壓縮方式:直接指向根節點if (x != parent[x]) {parent[x] = find(parent[x]);}return parent[x];}int merge(int x, int y, int length) {int rootx = find(x);int rooty = find(y);if (rootx != rooty) {if (rank[rootx] < rank[rooty]) {swap(rootx, rooty);}parent[rooty] = rootx;if (rank[rootx] == rank[rooty]) rank[rootx] += 1;// rooty的父節點設置為rootx,同時將rooty的節點數和邊長度累加到rootx,size[rootx] += size[rooty];len[rootx] += len[rooty] + length;// 如果某個連通分量的節點數 包含了所有節點,直接返回邊長度if (size[rootx] == num) return len[rootx];}return -1;} }; struct Edge {int start; // 頂點1int end; // 頂點2int len; // 長度 };class Solution { public:int minCostConnectPoints(vector<vector<int>>& points) {int res = 0;int n = points.size();Djset ds(n);vector<Edge> edges;// 建立點-邊式數據結構for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {Edge edge = {i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])};edges.emplace_back(edge);}}// 按邊長度排序sort(edges.begin(), edges.end(), [](const auto& a, const auto& b) {return a.len < b.len;});// 連通分量合并for (auto& e : edges) {res = ds.merge(e.start, e.end, e.len);if (res != -1) return res;}return 0;} };

總結

以上是生活随笔為你收集整理的算法第四版- 4.3的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。