并查集判断连通块数-克鲁斯卡尔 | #畅通工程#

畅通工程

https://www.nowcoder.com/practice/23c9fe571c1346bb91fdffea8a0b195f

#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
using namespace std;

class UnionFind {
  private:
    vector<int> f;
    vector<int> rank;
  public:
    UnionFind(int n): f(n+1,0), rank(n+1,0) {
        for (int i = 1; i <= n; i++) {
            f[i] = i;
        }
    }

    void merge(int x, int y) {
        int rx = find(x);
        int ry = find(y);
        if (rx != ry) {
            if (rank[rx] > rank[ry]) {
                f[ry] = rx;
            } else if (rank[rx] < rank[ry]) {
                f[rx] = ry;
            } else {
                f[ry] = rx;
                rank[rx]++;
            }
        }
    }

    int find(int x) {
        if (x != f[x]) {
            x = find(f[x]);
        }
        return f[x];
    }

    //统计并查集0节点下的节点个数
    int count() {
        int cnt = 0;
        int rt = find(0);
        for (int i = 0; i < f.size(); i++) {
            if (rt == find(i)) {
                cnt++;
            }
        }
        return cnt;
    }
    //统计联通块的个数
    int countConnected() {
        set<int> s;
        for (int i = 1; i <= f.size()-1; i++)
            s.insert(find(i));
        return s.size();
    }
    //a与b是否联通
    bool isConnect(int a, int b) {
        return find(a) == find(b);
    }
};
int main() {
    int n, m, a, b, c;
    while (cin >> n >> m) { // 注意 while 处理多个 case
        if (n == 0) break;
        //1.先把给出的数据merge下,检测是否可以联通乘一个
        UnionFind uf(m);
        vector<vector<int>> e;
        for (int i = 0; i < n; i++) {
            cin >> a >> b >> c;
            e.push_back({a, b, c});
            uf.merge(a, b);
        }
        if (uf.countConnected() == 1) {
            //2.然后恢复并查集,克鲁斯卡尔选择最小生成树的成本
            uf = UnionFind(m);
            sort(e.begin(), e.end(), [](auto a, auto b) {
                return a[2] < b[2];
            });
            // for_each(e.begin(), e.end(), [](auto a) {
            //     cout << a[0] << " " << a[1] << " " << a[2] << endl;
            // });
            int cnt = 0, p = 0, ans = 0;
            while (cnt < m - 1) {
                if (!uf.isConnect(e[p][0], e[p][1])) {
                    uf.merge(e[p][0], e[p][1]);
                    ans += e[p][2];
                    cnt++;
                }
                p++;
            }
            cout << ans << endl;
        } else
            cout << "?" << endl;

    }
}
// 64 位输出请用 printf("%lld")

全部评论

相关推荐

微风不断:兄弟,你把四旋翼都做出来了那个挺难的吧
点赞 评论 收藏
分享
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务