cf923Div3F题

using i64 = long long;
struct DSU {
    //f用来存储每个元素所述集合的根节点,siz用来存储每个集合的大小
    std::vector f, siz;
    //初始化时,将每个元素自己作为一个单独的集合,其根节点即为自己,
    //集合大小初始化为1。
    // 
    //在查找操作中按照路径压缩的方式找到根节点,并将
    //经过的节点直接连接到根节点上,以加速后续的查找操作
    //
    //在合并操作中,先判断两个元素的根节点是否相同,若相同
    //则表示它们已经属于同一个集合,直接返回失败,若不同,
    //则将两个集合合并,即将其中一恶搞集合的根节点指向另一个集合的
    //根节点,并更新集合大小
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        //f初始化
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    //查找x所在的集合的根节点,并返回根节点的编号
    int find(int x) {
        //寻找根节点
        //将x和f[x]都赋值为f[f[x]]
        while (x != f[x]) {
            x = f[x] = f[f[x]];
            //int root = f[x]; // 将x的父节点保存为root
            //int parent = f[root]; // 根节点的父节点也就是自己
            //f[x] = parent; // 更新x的父节点为根节点的父节点
            //x = parent; // 更新x的值为根节点的父节点
        }
        return x;
    }
    //判断元素(x,y)是否属于同一个集合,即它们的根节点是否相同
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    //将元素x和y所在的两个不想交集合合并成一个集合,并返回是否合并成功
    bool merge(int x, int y) {
        //找到x的根节点,找到y的根节点,不相同就把x的根节点赋给f[y]
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        //以x作为根节点把y连上去
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }

    int size(int x) {
        return siz[find(x)];
    }
};
void solve() {
    int n, m;
    //n个顶点,m条边
    std::cin >> n >> m;
    //存边
    std::vector> edges(m);
    for (int i = 0; i < m; i++) {
        //输入边
        int u, v, w;
        std::cin >> u >> v >> w;
        u--, v--;
        edges[i] = { w, u, v };
    }
    //从大到小排
    std::sort(edges.begin(), edges.end(), [](const auto& e1, const auto& e2) {
        return std::get<0>(e1) > std::get<0>(e2);
        });
    //初始化答案
    int ans = 1E9;
    DSU dsu(n);
    //起点,终点
    int U, V;
    std::vector> adj(n);
    for (auto it = edges.begin(); it != edges.end(); ++it) {
        int w = std::get<0>(*it);
        int u = std::get<1>(*it);
        int v = std::get<2>(*it);
        //已经在集合中,从大到小,所以每次更新都是包含更小边的集合
        if (!dsu.merge(u, v)) {
            ans = w;
            U = u;
            V = v;
        }
        else {
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
    }

    std::vector path;
    auto dfs = [&](auto self, int x, int p) -> bool {
        //找到终点
        if (x == V) {
            path.push_back(x);
            return true;
        }
        //x表示节点x的邻接表
        for (auto y : adj[x]) {
            //p是上一个点,如果是这个点就跳过
            if (y == p) {
                continue;
            }
            //一路向下遍历,每个点都是独一无二的,找到终点就是一个完整的循环
            if (self(self, y, x)) {
                path.push_back(x);
                return true;
            }
        }
        return false;
    };
    //起点开始,没有前一个点
    dfs(dfs, U, -1);

    std::cout << ans << " " << path.size() << "\n";
    for (auto x : path) {
        std::cout << x + 1 << " \n"[x == path.back()];
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t;
    std::cin >> t;

    while (t--) {
        solve();
    }

    return 0;
}

你可能感兴趣的:(算法,c++,数据结构,并查集)