1. 程式人生 > 其它 >【leetcode】1319連通網路的操作次數 | 尋找圖中的連通分量 | 深度優先搜尋 | 並查集

【leetcode】1319連通網路的操作次數 | 尋找圖中的連通分量 | 深度優先搜尋 | 並查集

技術標籤:leetcodeC++演算法dfs

誰能想到wzq的審美跟著戰哥走呢

演算法考完到現在頹廢了10天,小王又回來了。刷leeetcode明顯覺得力不從心了,還好以前的功力也不是很深厚,慢慢補一補,很快能補回來的。

題目

用乙太網線纜將 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. 1 <= n <= 105
  2. 1 <= connections.length <= min(n*(n-1)/2, 105)
  3. connections[i].length == 2
  4. 0 <= connections[i][0], connections[i][1] < n
  5. connections[i][0] != connections[i][1]
  6. 沒有重複的連線。
  7. 兩臺計算機不會通過多條線纜連線。

題解

這道題分析一下,很容易得到我們要找這個圖中有多少連通分量。具體證明過程挺容易想的,就不贅述了
這也不放本菜雞寫的渣渣了(沒通過,改改還是沒通過,放棄了,嗚嗚嗚嗚嗚嗚嗚)

法一:深度優先搜尋

初始時所有節點的狀態均為「待搜尋」。我們每次選擇一個「待搜尋」的節點,從該節點開始進行深度優先搜尋,並將所有搜尋到的節點的狀態更改為「已搜尋」,這樣我們就找到了一個連通分量。

class Solution {
private:
    vector<vector<int>> edges;
    vector<int> used;//已搜尋

public:
    void dfs(int u) {
        used[u] = true;
        for (int v: edges[u]) {
            if (!used[v]) {
                dfs(v);
            }
        }
    }
    
    int makeConnected(int n, vector<vector<int>>& connections) {
        if (connections.size() < n - 1) {
            return -1;
        }

        edges.resize(n);//設定大小為n
        for (const auto& conn: connections) {
            edges[conn[0]].push_back(conn[1]);
            edges[conn[1]].push_back(conn[0]);
        }
        
        used.resize(n);
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            if (!used[i]) {
                dfs(i);
                ++ans;
            }
        }
        
        return ans - 1;
    }
};

作者:LeetCode-Solution
連結:https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected/solution/lian-tong-wang-luo-de-cao-zuo-ci-shu-by-leetcode-s/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

法二:並查集

關於並查集是什麼

並查集,在一些有N個元素的集合應用問題中,我們通常是在開始時讓每個元素構成一個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其間要反覆查詢一個元素在哪個集合中。這一類問題近幾年來反覆出現在資訊學的國際國內賽題中,其特點是看似並不複雜,但資料量極大,若用正常的資料結構來描述的話,往往在空間上過大,計算機無法承受;即使在空間上勉強通過,執行的時間複雜度也極高,根本就不可能在比賽規定的執行時間(1~3秒)內計算出試題需要的結果,只能用並查集來描述。
並查集是一種樹型的資料結構,用於處理一些不相交集合(Disjoint Sets)的合併及查詢問題。常常在使用中以森林來表示。
摘自C++並查集

// 並查集模板
class UnionFind {
public:
    vector<int> parent;
    vector<int> size;
    int n;
    // 當前連通分量數目
    int setCount;
    
public:
    UnionFind(int _n): n(_n), setCount(_n), parent(_n), size(_n, 1) {
        iota(parent.begin(), parent.end(), 0);
    }
    
    int findset(int x) {
        return parent[x] == x ? x : parent[x] = findset(parent[x]);
    }
    
    bool unite(int x, int y) {
        x = findset(x);
        y = findset(y);
        if (x == y) {
            return false;
        }
        if (size[x] < size[y]) {
            swap(x, y);
        }
        parent[y] = x;
        size[x] += size[y];
        --setCount;
        return true;
    }
    
    bool connected(int x, int y) {
        x = findset(x);
        y = findset(y);
        return x == y;
    }
};

class Solution {
public:
    int makeConnected(int n, vector<vector<int>>& connections) {
        if (connections.size() < n - 1) {
            return -1;
        }

        UnionFind uf(n);
        for (const auto& conn: connections) {
            uf.unite(conn[0], conn[1]);
        }

        return uf.setCount - 1;
    }
};

作者:LeetCode-Solution
連結:https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected/solution/lian-tong-wang-luo-de-cao-zuo-ci-shu-by-leetcode-s/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。