LeeCode 685 dfs + 并查集

题意

传送门 LeeCode 685

题解

此时图中一定出现环。

考虑所有节点度都小于等于 1 1 的情况,此时环首尾相连,环上任意边均为可能答案,取索引值最大的即可;用并查集合并节点,第一次出现两端节点连通的边即答案。

考虑存在度为 2 2 的结点的情况,此时答案为指向该节点的边之一;枚举删边,从根节点 dfs 即可,若不能遍历全部节点,则当前删除边非答案;若 2 2 条边枚举删除后 dfs 都满足条件,取索引值最大的即可。

const int MAX_N = 1e3 + 1;

class Solution {
private:
	// 并查集模板
    int par[MAX_N];
    int rank[MAX_N];

    void union_find_init(int n){
	    for(int i = 0; i < n; i++){
		    par[i] = i;
		    rank[i] = 0;
	    }
    }
    int find(int x){
    	if(par[x] == x) return x;
	    return par[x] = find(par[x]);
    }
    bool same(int x, int y){
    	return find(x) == find(y);
    }
    void unite(int x, int y){
	    x = find(x), y = find(y);
	    if(x == y) return;
	    if(rank[x] > rank[y]) par[y] = x;
	    else{
	    	if(rank[x] == rank[y]) ++rank[y];
		    par[x] = y;
	    }
    }
    
    vector<int> G[MAX_N]; // 有向图
    bool used[MAX_N]; // dfs 标记
    int cnt; // 连通节点数

    void dfs(int u){
        used[u] = true;
        ++cnt;
        for(int i = 0; i < G[u].size(); i++){
            int v = G[u][i];
            if(!used[v]) dfs(v);
        }
    }
    
    void init_dfs(int v, int e, int del, vector<vector<int>>& edges){
        memset(used, 0, sizeof(used));
        cnt = 0;
        for(int i = 1; i <= v; i++) G[i].clear();
        for(int j = 0; j < e; j++){
            if(j != del) G[edges[j][0]].push_back(edges[j][1]);
        }
    }

public:
    vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
        vector<int> res(2);
        int sz = edges.size();
        vector<int> d(sz + 1), pre(sz + 1);
        int e = -1;
        for(int i = 0; i < sz; i++){
            int u = edges[i][0], v = edges[i][1];
            if(++d[v] == 2){
                e = i;
            }
            else pre[v] = i;
        }
        // 处理出现度为 2 的节点的情况
        if(e != -1){
            int s;
            for(int i = 1; i <= sz; i++) {
                if(d[i] == 0){
                    s = i;
                    break;
                }
            }
            int e2 = pre[edges[e][1]];
            init_dfs(sz, sz, e, edges);
            dfs(s);
            if(cnt < sz) res = edges[e2];
            else{
                init_dfs(sz, sz, e2, edges);
                dfs(s);
                if(cnt < sz) res = edges[e];
                else res = e > e2 ? edges[e] : edges[e2];
            }
            return res;
        }
        // 所有节点度小于等于 1, 并查集处理即可
        union_find_init(sz);  
        for(int i = 0; i < sz; i++){
            int u = edges[i][0], v = edges[i][1];
            if(!same(u, v)){
                unite(u, v);
            }
            else{
                res = edges[i];
                break;
            }
        }
        return res;
    }
};
发布了110 篇原创文章 · 获赞 1 · 访问量 2037

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/105587728