Joint query set 1 & dfs & bfs & unionMerge & bipartite graph

0 some basics

Judge whether the whole graph is connected

Use dfs to judge whether the whole graph is connected:

        // if not connected, return false
        vecctor<int> stack = {0};
        vector<bool> vis(graph.size(), false);
        vis[0] = true;
        int visCnt = 1;
        // dfs to check if connected
        while(!stack.empty()) {
            int top = stack.back();
            bool allVisited = true;
            for(int i = 0; i < graph[top].size(); ++i) {
                if(!vis[graph[top][i]]) {
                    stack.emplace_back(graph[top][i]);
                    vis[graph[top][i]] = true;
                    allVisited = false;
                    visCnt++;
                    break;
                }
            }
            if(allVisited) {
                stack.pop_back();
            }
        }

        if(visCnt != n) return false;

It is also possible to use bfs, such as the following 0684 redundant link

Use of parallel query set

It mainly aggregates the associated edges into the same root, which can compress the path and accelerate the find process

    int find(vector<int>& parent, int curNode) {
        while(parent[curNode] != curNode) {
            parent[curNode] = parent[parent[curNode]];
            curNode = parent[curNode];
        }
        return curNode;
    }

    void unionMerge(vector<int>& parent, int from, int to) {
        int x = find(parent, from);
        int y = find(parent, to);
        
        if(x != y) {
            parent[x] = y;
        }
    }

Bipartite graph judgment

  • 1 general ideas
    Using bfs traversal, consider the parity level. The odd level is node set A and the even level is node set B. finally, scan all edges to determine whether any edge is located in AB rather than across ab,
    If yes, it returns false, otherwise it returns true

  • 2. Joint search set

  • 3 dfs

Example explanation

0785 bipartite drawing

1 topic

https://leetcode-cn.com/problems/is-graph-bipartite/

2 problem solving ideas

  • 1 general ideas
    Using bfs traversal, consider the parity level. The odd level is node set A and the even level is node set B. finally, scan all edges to determine whether any edge is located in AB rather than across ab,
    If yes, it returns false, otherwise it returns true;
    At the same time, pay attention to the empty judgment of the adjacency table. A graph with 0 empty edges can be bisected!
class Solution {
public:
    bool isBipartite(vector<vector<int>>& graph) {
        int n = graph.size();
        
        int edgeNum = 0;
        for(int u = 0; u < n; ++u) {
            for(int v = 0; v < graph[u].size(); ++v) {
                ++edgeNum;
            }
        }
        if(edgeNum == 0) return true;

        // if not connected, return false
        vector<int> stack = {0};
        // vector<bool> vis(graph.size(), false);
        // vis[0] = true;
        // int visCnt = 1;
        // // dfs to check if connected
        // while(!stack.empty()) {
        //     int top = stack.back();
        //     bool allVisited = true;
        //     for(int i = 0; i < graph[top].size(); ++i) {
        //         if(!vis[graph[top][i]]) {
        //             stack.emplace_back(graph[top][i]);
        //             vis[graph[top][i]] = true;
        //             allVisited = false;
        //             visCnt++;
        //             break;
        //         }
        //     }
        //     if(allVisited) {
        //         stack.pop_back();
        //     }
        // }

        // if(visCnt != n) return false;

        // bfs to judge biPartitable
        deque<int> q = {};


        vector<bool> vis2(graph.size(), false);
            unordered_set<int> biPart1 = {};
            unordered_set<int> biPart2;
            deque<int> level = {};
        int bfsNum = 0;
        
        while(bfsNum != n) {        

            for(int i = 0; i < n; ++i) {
                if(!vis2[i]) {
                    q.emplace_back(i);
                    level.emplace_back(0);
                    biPart1.insert(i);
                    ++bfsNum;
                    vis2[i] = true;
                    break;
                }
            }
            while(!q.empty()) {
                int front = q.front();
                for(int i = 0; i < graph[front].size(); ++i) {
                    if(!vis2[graph[front][i]]) {
                        q.emplace_back(graph[front][i]);
                        ++bfsNum;
                        level.emplace_back(level.front() + 1);
                        if(level.front() % 2 == 0) {
                            biPart2.insert(graph[front][i]);
                        } else {
                            biPart1.insert(graph[front][i]);
                        }
                        vis2[graph[front][i]] = true;          
                    }
                }
                q.pop_front();
                level.pop_front();
            }
            // for(auto& i : biPart1) {
            //     std::cout << i << " ";
            // }
            // cout << endl;
            // for(auto& i : biPart2) {
            //     std::cout << i << " ";
            // }
            // cout << endl;
            
            for(int u = 0; u < n; ++u) {
                for(int v = 0; v < graph[u].size(); ++v) {
                    if((biPart2.count(u) == 1 && biPart2.count(graph[u][v]) == 1) || \
                    (biPart1.count(u) == 1 && biPart1.count(graph[u][v]) == 1)) {
                        return false;
                    }
                }
            }
        }


        return true;
    }
}

0765minSwapsCouple

1 topic

https://leetcode-cn.com/problems/couples-holding-hands/

2 problem solving ideas

  • 0 sentence: find a connected subgraph, and the sum of the number of nodes of each connected subgraph - 1 is the result
  • 1 general ideas
    For each 2k - 2 and 2k - 1 seat, find the couple of people on 2k - 2, change it to 2k - 1 position, and traverse k to o(n**2)
  • 2 improvement ideas
    Considering the fact that:
    If there are 8 seats, and then all couples cannot sit adjacent, consider: create an edge for two adjacent people on 2k-2 and 2k-1 seats, but not couples, and the node is the cp serial number of couples
    (for example, couples with serial numbers 4 and 5 correspond to a node, which is 5 / 2 = = 4 / 2 = = 2)
    Then we can know that this graph has only one connected subgraph, and then the number of nodes is 4, then the number of exchanges is 4-1 = 3,

Easily confused: at least one couple can be completed in one exchange, only the last exchange can complete two teams of couples, and the rest can only be completed once
So the minimum number of exchanges, in fact, don't change it repeatedly. What you calculate is the minimum

class Solution {
public:
    int minSwapsCouples(vector<int>& row) {
        // Easily confused: at least one couple can be completed in one exchange, only the last exchange can complete two teams of couples, and the rest can only be completed once
        // So the minimum number of exchanges, in fact, don't change it repeatedly. What you calculate is the minimum
        
        // First of all, note that two couples are regarded as a node. If couples who do not belong to a pair sit in two positions of 2K - 2 and 2K - 1, they will connect a line
        vector<int> parent(row.size() / 2);
        for(int i = 0; i < row.size() / 2; ++i) {
            parent[i] = i;
        }

        for(int i = 0; i < row.size(); i += 2) {
            int nodeIdx = i / 2;
            unionMerge(parent, row[i] / 2, row[i + 1] / 2);
            // std::cout << row[i] / 2<< " -> " << row[i + 1] / 2 << std::endl;
        }

        // Find all connected subgraphs in the figure above. Subtract 1 from the number of nodes on the edges of all connected subgraphs to obtain the number of exchanges required for all couples to sit adjacent to each other in a subgraph
        unordered_map<int, int> rootIdxToCnt;
        for(int i = 0; i < row.size() / 2; ++i) {
            rootIdxToCnt[find(parent, i)] ++;
            // std::cout << i << " -> " << find(parent, i) << std::endl;
        }

        int res = 0;
        for(auto& it : rootIdxToCnt) {
            res += it.second - 1;
        }
        return res;

    }

    int find(vector<int>& parent, int curNode) {
        while(parent[curNode] != curNode) {
            parent[curNode] = parent[parent[curNode]];
            curNode = parent[curNode];
        }
        return curNode;
    }

    void unionMerge(vector<int>& parent, int from, int to) {
        int x = find(parent, from);
        int y = find(parent, to);
        
        if(x != y) {
            parent[x] = y;
        }
    }
}

0684 redundant link

1 Title Description

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

2 problem solving ideas

Using the union search set, each edge is regarded as a subtree, and then one edge is added to the tree. When the two vertices of the added edge belong to the same subtree, it is considered that there is a loop, and the redundant edge is returned.
See the following code:

class Solution {
public:
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        tree.resize(edges.size() * 2 + 1, -1);
        subTreeSize.resize(edges.size() * 2 + 1, 1);
        
        vector<int> res;
        for(auto& c : edges) {
            if(!unionMerge(c[0], c[1], tree)) {
                res = c;
                break;
            }
        }
        return res;
    }
    
    int find(int tar, vector<int>& tree) {
        int curFather = tree[tar];
        if (curFather < 0) { // tar has no father, so he is the root
            tree[tar] = tar;
            return tar;
        }
        if(tar != curFather) {
            tree[tar] = find(curFather, tree); // compress the data path
        }
        return tree[tar];
    }
    
    
    bool unionMerge(int x, int y, vector<int>& tree) {
        int fx = find(x, tree);
        int fy = find(y, tree);
        if(fx == fy) {
            return false; // x, y are in the same tree, need no merge
        }
        if(subTreeSize[fx] >= subTreeSize[fy]){ // merge by rank of the sub Tree
            tree[fy] = fx;
            subTreeSize[fx] += subTreeSize[fy];
        } else {
            tree[fx] = fy;
            subTreeSize[fy] += subTreeSize[fx];
        }
        return true;
    }
    
    vector<int> subTreeSize;
    vector<int> tree;
};

Tags: Algorithm data structure Graph Theory LC

Posted on Mon, 29 Nov 2021 13:23:28 -0500 by php_tom