【ACM】- HDU-3371 Connect the Cities 【最小生成树】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26398495/article/details/82708510
题目链接
题目分析

最小生成树问题;

解题思路

把已连通的结点间的距离(边权)令为0,统一加入边集合;
Kruskal算法 + 并查集解决;Kruskal算法中边的排序用容器priority_queue(堆结构)实现;


AC程序(C++)
/**********************************
*@ID: 3stone
*@ACM: HDU-3371 Connect the Cities
*@Time: 18/9/14
*@IDE: VSCode + clang++
***********************************/
#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
const int maxn = 510;

struct edge {
    int u, v, cost;
    edge() {}
    edge(int _u, int _v, int _cost) : u(_u), v(_v) , cost(_cost) {}
    bool operator < (const edge& n) const {
        return cost  > n.cost;
    }
};

int T, N, M, K;
int far[maxn]; //并查集

int find_root(int a) {
    int root = a;
    while(root != far[root]) root = far[root];
    while(a != far[a]) {
        int cur = a;
        a = far[a];
        far[cur] = root;
    }
    return root;
}

void union_set(int a, int b) {
    int root_a = find_root(a);
    int root_b = find_root(b);
    if(root_a != root_b) {
        far[root_b] = root_a;
    }
}

int Kruskal(priority_queue<edge> E) {

    int edge_num = 0, ans = 0;
    while(!E.empty()) {
        edge e = E.top(); E.pop();
        int root_u = find_root(e.u);
        int root_v = find_root(e.v);
        if(root_u != root_v) {
            edge_num++;
            ans += e.cost;
            union_set(root_u, root_v);
            if(edge_num == N - 1) break;
        }
    }//while
    if(edge_num == N - 1) return ans;
    else return -1;
}

int main() {
    int t, a, b, cost;
    scanf("%d", &T);
    while(T-- > 0) {
        scanf("%d%d%d", &N, &M, &K);
        priority_queue<edge> E; //边集合(堆结构,省去排序)
        for(int i = 0; i < maxn; i++) far[i] = i;//初始化并查集
        for(int i = 0; i < M; i++) { //输入边信息
            scanf("%d%d%d", &a, &b, &cost);
            E.push(edge(a, b, cost));
        }

        vector<int> connected; //记录连通分量的结点
        for(int i = 0; i < K; i++) { //输连通分量信息
            scanf("%d", &t);//结点数
            connected.clear();
            for(int j = 0; j < t; j++) {
                scanf("%d", &a);
                connected.push_back(a);
            }
            //已连通结点当做边权为0的边加入集合
            for(int j = 0; j < connected.size(); j++) {
                for(int l = j + 1; l < connected.size(); l++) {
                    E.push(edge(connected[j], connected[l], 0));
                }
            }
        }//for - i

        int ans = Kruskal(E);
        printf("%d\n", ans);

    }//while

    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_26398495/article/details/82708510