1. 程式人生 > 實用技巧 >[NOIP模擬賽][分層圖][狀態壓縮] 密室

[NOIP模擬賽][分層圖][狀態壓縮] 密室

https://leetcode-cn.com/problems/redundant-connection-ii/

對於有向圖的樹,如果增加一條有向邊,則會出現兩種情況
第一種為形成一個點有兩個father
1.有有向環,無環
第二種為有環


class Solution {
private:
    static const int N = 1010; // 如題:二維陣列大小的在3到1000範圍內
    int father[N];
    int n; // 邊的數量
    // 並查集初始化
    void init() {
        for (int i = 1; i <= n; ++i) {
            father[i] = i;
        }
    }
    // 並查集裡尋根的過程
    int find(int u) {
        return u == father[u] ? u : father[u] = find(father[u]);
    }
    // 將v->u 這條邊加入並查集
    void join(int u, int v) {
        u = find(u);
        v = find(v);
        if (u == v) return ;
        father[v] = u;
    }
    // 判斷 u 和 v是否找到同一個根
    bool same(int u, int v) {
        u = find(u);
        v = find(v);
        return u == v;
    }
    // 在有向圖裡找到刪除的那條邊,使其變成樹
    vector<int> getRemoveEdge(const vector<vector<int>>& edges) {
        init(); // 初始化並查集
        for (int i = 0; i < n; i++) { // 遍歷所有的邊
            if (same(edges[i][0], edges[i][1])) { // 構成有向環了,就是要刪除的邊
                return edges[i];
            }
            join(edges[i][0], edges[i][1]);
        }
        return {};
    }

    // 刪一條邊之後判斷是不是樹
    bool isTreeAfterRemoveEdge(const vector<vector<int>>& edges, int deleteEdge) {
        init(); // 初始化並查集
        for (int i = 0; i < n; i++) {
            if (i == deleteEdge) continue;
            if (same(edges[i][0], edges[i][1])) { // 構成有向環了,一定不是樹
                return false;
            }
            join(edges[i][0], edges[i][1]);
        }
        return true;
    }
public:

    vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
        int inDegree[N] = {0}; // 記錄節點入度
        n = edges.size(); // 邊的數量
        for (int i = 0; i < n; i++) {
            inDegree[edges[i][1]]++; // 統計入度
        }
        vector<int> vec; // 記錄入度為2的邊(如果有的話就兩條邊)
        // 找入度為2的節點所對應的邊,注意要倒敘,因為優先返回最後出現在二維陣列中的答案
        for (int i = n - 1; i >= 0; i--) {
            if (inDegree[edges[i][1]] == 2) {
                vec.push_back(i);
            }
        }
        // 處理圖中情況1 和 情況2
        // 如果有入度為2的節點,那麼一定是兩條邊裡刪一個,看刪哪個可以構成樹
        if (vec.size() > 0) {
            if (isTreeAfterRemoveEdge(edges, vec[0])) {
                return edges[vec[0]];
            } else {
                return edges[vec[1]];
            }
        }
        // 處理圖中情況3
        // 明確沒有入度為2的情況,那麼一定有有向環,找到構成環的邊返回就可以了
        return getRemoveEdge(edges);

    }
};

作者:carlsun-2
連結:https://leetcode-cn.com/problems/redundant-connection-ii/solution/685-rong-yu-lian-jie-iibing-cha-ji-de-ying-yong-xi/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。