演算法刷題筆記 - 連線所有點的最小費用(最小生成樹)
阿新 • • 發佈:2021-01-20
連線所有點的最小費用
- 來源 : LeetCode - 連線所有點的最小費用
- 難度 : 中等
- 標籤 : 最小生成樹
題目描述
-
給你一個points陣列,表示2D平面上的一些點,其中points[i]為第i個點。
-
連線點[xi, yi]和點 [xj, yj]的費用為它們之間的 曼哈頓距離 : |xi - xj| + |yi - yj| ,其中 |val| 表示 val的絕對值。
-
請你返回將所有點連線的最小總費用。只有任意兩點之間有且僅有一條簡單路徑時,才認為所有點都已連線。
=>
解法構思
結合圖論或資料結構的有關知識,顯然可以想到是最小生成樹問題
Prim演算法介紹 :
Prim演算法尋找最小生成樹的思路是假想有兩個集合,一個為已經參與建樹的點集,一個為未參與建樹的點集,每次都從已建樹點集中的點到為建樹點集中的點的所有邊中選擇權重最小的一個,這條邊就加入構建生成樹,相應的,這條邊的終點就從未建樹點集移到另一集合中, 如此反覆直到所有點都參與建樹則停止, 在進行過程中, 記錄生成樹的有關資訊, 對於此題僅需要將每次選出的最小邊的權重累加, 最後得到此題結果。
- 為了提高效率, 利用一表記錄每個未建樹點形成的最小權值(每個未建樹點, 其到每個已建樹點有邊, 記錄其中最小者, 每個未建樹點都有這麼一條記錄), 每當生成樹增加一個點時, 更新此表。
上手程式設計
// 曼哈頓距離 #define PRICE(p1, p2) ( abs( (p1)[0] - (p2)[0] ) + abs( (p1)[1] - (p2)[1] ) ) int minCostConnectPoints(vector<vector<int>>& points) { const int N = points.size(); int res = 0; // 結果 vector<vector<int>> W(N, vector<int>(N, 0)) // 鄰接矩陣; vector<int> lowCost(N, 0); // 最小權值表 vector<char> okSet(N, 0); // 記錄每個點是否已建樹, 是為1, 否為0 // 建立鄰接矩陣 for (int i = 0; i < N; ++i) for (int j = i + 1; j < N; ++j) W[i][j] = W[j][i] = PRICE(points[i], points[j]); // 從0號點開始建樹 okSet[0] = true; // 初始化 / 構建此時的最小權值表 for (int i = 1; i < N; ++i) lowCost[i] = W[0][i]; // 一共需要再找出N-1個點建樹 for (int cnt = 1; cnt < N; ++cnt) { // 此次選出的最小權值, 及對應的出發點的序號(此點即即將參與建樹的點) int min_price = INT_MAX, min_targetIndex = 0; // 找連線兩個集合點的最小權值的邊 for (int i = 0; i < N; ++i) { if (!okSet[i]) { // 僅處理 從未建樹點出發的邊 if (lowCost[i] < min_price) { min_price = lowCost[i]; min_targetIndex = i; } } } // 累計最小權值 res += min_price; // 建樹點集中加入剛選出的點 okSet[min_targetIndex] = true; // 更新lowCost表 for (int i = 0; i < N; ++i) if (!okSet[i]) lowCost[i] = min(lowCost[i], W[i][min_targetIndex]); } return res; }