PigyChan_LeetCode 1319. 連通網路的操作次數

PigyChan發表於2020-10-24

1319. 連通網路的操作次數

難度中等

題目

用乙太網線纜將 n 臺計算機連線成一個網路,計算機的編號從 0 到 n-1。線纜用 connections 表示,其中 connections[i] = [a, b] 連線了計算機 a 和 b。
網路中的任何一臺計算機都可以通過網路直接或者間接訪問同一個網路中其他任意一臺計算機。
給你這個計算機網路的初始佈線 connections,你可以拔開任意兩臺直連計算機之間的線纜,並用它連線一對未直連的計算機。請你計算並返回使所有計算機都連通所需的最少操作次數。如果不可能,則返回 -1 。

示例 1:
在這裡插入圖片描述

輸入:n = 4, connections = [[0,1],[0,2],[1,2]]
輸出:1
解釋:拔下計算機 1 和 2 之間的線纜,並將它插到計算機 1 和 3 上。
示例 2:
在這裡插入圖片描述

輸入:n = 6, connections = [[0,1],[0,2],[0,3],[1,2],[1,3]]
輸出:2
示例 3:

輸入:n = 6, connections = [[0,1],[0,2],[0,3],[1,2]]
輸出:-1
解釋:線纜數量不足。
示例 4:

輸入:n = 5, connections = [[0,1],[0,2],[3,4],[2,3]]
輸出:0

提示:
*
1 <= n <= 10^5
*
1 <= connections.length <= min(n*(n-1)/2, 10^5)
*
connections[i].length == 2
*
0 <= connections[i][0], connections[i][1] < n
*
connections[i][0] != connections[i][1]
*
沒有重複的連線。
*
兩臺計算機不會通過多條線纜連線。

思路1.0:

從兩個例子推測,只要處理得出題目所給的圖的頂點數V(電腦終端)和邊數E(網路電纜),然後判斷 V-1==E ? TBD : -1;
但讓我困擾的是,會不會出現情況"要移動數次邊才能連結上一個孤立點"…應該不存在吧,題目都說了是次數最少,每連結一個孤立點肯定要最少的移動次數.
那麼本題就轉換成:1)有幾個頂點.2)有幾條邊.3)當前已連線了幾個點.


阿西吧!無從下手啊!我還是想得太簡單了,看了下題解發現需要用到並查集的知識,這就去定點爆破.


並查集

一個具有n個元素的集合U,與一個具有r個關係的集合R摩擦出的故事.
舉例說:
U{0,1,2,3,4} R{(0,1),(0,2),(3,4)},R中的關係稱為等價關係
那麼{0,1,2}和{3,4}就分屬兩個等價類.我們如何從最開始孤立的5個點,通過R中的若干關係慢慢地組成一個個越來越龐大的等價類呢?這就需要這麼幾個函式來幫忙了.
(1) find(a)函式,用來查詢a點屬於哪個等價類.
(2)combine(a,b)函式,用來合併兩個具有等價關係的等價類

一個肥腸牛逼的大佬對並查集的解釋


程式碼1.0

  class Solution {
  public:
      vector<int> equClass;
      vector<int> equClassSZ;
      int classNum;
      int moreLine;
      int makeConnected(int n, vector<vector<int>>& connections) {
          //線纜不夠,pass
          if (connections.size() < n - 1)
              return -1;
          //對幾個全域性變數進行初始化
          equClass.resize(n);
          for (int i = 0; i < n; ++i)
              equClass[i] = i;
          equClassSZ.resize(n, 1);
          classNum = n;
          moreLine = 0;
          for (const auto& i : connections) {
              combine(i[0],i[1]);
          }
          if (moreLine < classNum - 1) return -1;
          
          return classNum - 1;
      }
      //find(int value)函式找到n所在的等價類(n的根,標識等價類)
      int find(int value) {
          while (value != equClass[value])
              value = equClass[value];
          return value;
      }
      //combine(int valueA,int valueB)函式合併valueA和valueB(遵守小樹合到大樹的原則)
      void combine(int valueA, int valueB) {
          int rootA = find(valueA);
          int rootB = find(valueB);
          //兩值已經是同一等價類了,我們不再操作
          if (rootA == rootB) {
              ++moreLine;
              return;
          }
          //小樹合到大樹中去
          if (equClassSZ[valueA] < equClassSZ[valueB]) {
              equClass[rootA] = rootB;
              equClassSZ[valueB] += equClassSZ[valueA];
          }
          else {
              equClass[rootB] = rootA;
              equClassSZ[valueA] += equClassSZ[valueB];
          }
          //當前戰場上獨立的等價類又少了一個
          --classNum;
      }
  };

啊哈哈哈哈!!!完成並查集首殺!!!
在這裡插入圖片描述

相關文章