每日一题:leetcode1579.保证图可完全遍历

题目描述

在这里插入图片描述

题目分析

非常惭愧,感觉自己有点畏难心理,看到是困难题第一个想法是自己想不出来。。。
因为自己认为自己做不出来,所以完全不能进行思考,稍微思考一下就觉得不行不行。
我也想到了分别用两个并查集判断各自可以去掉多少边,但是一想到还有公共边,就感觉一头乱麻,不知道从什么地方下手。
当时主要感觉困难的地方在于,如果两个人去掉的公共边不一样,则没有办法统一。
看了题解以后我觉得我这个想法离正确的思路已经非常近了,抓住公共边这个矛盾再进行思考应该就可以。
另一方面还应该有跳出思维定势的能力,不能因为题目中先说的是私有边再说的是公有边自己也只能这样思考,要把条件翻来覆去进行转换才行。
回过头观察公共边:很容易觉得公共边比私有边重要(因为公有边两个人都可以用
我当时也想到公共边比较重要,但是又想到两个人可能用的公共边不一样。这其实就是思维定势:主观觉得一定要先使用私有边,不够的再是使用公有边。
如果先尽量使用公有边再使用私有边的话一切都将豁然开朗。因为在图的连通中使用并查集就表征了边的极大诱导子图(好像是这么说,可能不准确,意思就是每个连通分量已经是最大了)。因此丢去的公有边无论是哪条都无所谓(不会影响连通情况)。然后再分别考虑私有边。

AC代码

class UnionSet {
public:
    int n;
    int setCount;
    vector<int> father;
    vector<int> size;
    UnionSet(int _n):n(_n),setCount(_n),father(_n),size(_n, 1) {
        iota(father.begin(), father.end(), 0);
    }
    UnionSet() {

    }
    int root(int x) {
        return x == father[x] ? x : father[x] = root(father[x]);
    }
    bool unite(int x, int y) {
        x = root(x);
        y = root(y);
        if (x == y) {
            return false;
        }
        if (size[x] < size[y]) {
            swap(x, y);
        }
        father[y] = x;
        size[x] += size[y];
        --setCount;
        return true;
    }
};
class Solution {
public:
    int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
        for (auto &edge : edges) {
            --edge[1];
            --edge[2];
        }
        int ans = 0;
        UnionSet us(n);
        // UnionSet us_a(n);
        // UnionSet us_b(n);
        for (auto &edge : edges) {
            if (edge[0] == 3) {
                //遍历公共边
                if (us.unite(edge[1], edge[2])) {
                    // us_b.unite(edge[1], edge[2]);
                } else {
                    ++ans;
                }
            }
        }

        //计算Alice的联通
        UnionSet us_a;
        us_a.n = n;
        us_a.father = us.father;
        us_a.setCount = us.setCount;
        us_a.size = us.size;
        for (auto &edge : edges) {
            if (edge[0] == 1) {
                if (us_a.unite(edge[1], edge[2])) {
                    
                } else {
                    ++ans;
                }
            }
        }
        
        if (us_a.setCount != 1) {
            return -1;
        }

        //计算Bob的联通
        UnionSet us_b;
        us_b.n = n;
        us_b.father = us.father;
        us_b.setCount = us.setCount;
        us_b.size = us.size;
        for (auto &edge : edges) {
            if (edge[0] == 2) {
                if (us_b.unite(edge[1], edge[2])) {
                    
                } else {
                    ++ans;
                }
            }
        }

        if (us_b.setCount != 1) {
            return -1;
        }

        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值