列表

详情


NC159. 最小生成树

描述

一个有 n 户人家的村庄,有 m 条路相互连接着。村里现在要修路,每条路都有一个成本价格,现在请你帮忙计算下,最少需要花费多少钱,就能让这 n 户人家连接起来。

为一个二维数组,每个元素是一个长度为 3 的一维数组 表示村庄 和村庄 有一条路,修这条路的成本价格为 .

每户之间可能有多条道路连接,但不可能自己与自己相连

数据范围:  ,  , 
进阶: 时间复杂度 , 空间复杂度

示例1

输入:

3,3,[[1,3,3],[1,2,1],[2,3,1]]

输出:

2

示例2

输入:

2,1,[[1,2,1]]

输出:

1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 3ms, 内存消耗: 376KB, 提交时间: 2021-07-13

class Solution {
public:
    struct Element {
        int value;
        Element *next;
        Element() : next(this) {}
        Element(int v) : value(v), next(this) {}
    };
    struct UnionFindSet {
        vector<Element *> pElement_vec;
        unordered_map<Element *, int> pElement_i_unmap;
        UnionFindSet(int n){
            int i = 0;
            while(i < n)
            {
                Element *pElement = new Element(i);
                pElement_vec.push_back(pElement);
                pElement_i_unmap[pElement] = 1;
                i++;
            }
        }
        ~UnionFindSet(){
            for(auto pElement : pElement_vec)
                delete pElement;
        }
        
        Element *find_Head(Element *pElement){
            if(pElement->next == pElement) return pElement;
            
            Element *p = pElement->next;
            while(p != p->next) p = p->next;
            while(pElement->next != p)
            {
                Element *p_tmp = pElement->next;
                pElement->next = p;
                pElement = p_tmp;
            }
            return p;
        }
        
        bool union_set(int lhs, int rhs)
        {
            Element *lhs_head = find_Head( pElement_vec[lhs] );
            Element *rhs_head = find_Head( pElement_vec[rhs] );
            if(lhs_head == rhs_head) return false;
            Element *many_head = 
                pElement_i_unmap[lhs_head] >= pElement_i_unmap[rhs_head] ? lhs_head : rhs_head;
            Element *few_head = many_head == lhs_head ? rhs_head : lhs_head;
            pElement_i_unmap[many_head] += pElement_i_unmap[few_head];
            pElement_i_unmap.erase( few_head );   few_head->next = many_head;
            return true;
        }
    };
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 返回最小的花费代价使得这n户人家连接起来
     * @param n int n户人家的村庄
     * @param m int m条路
     * @param cost intvector<vector<>> 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价
     * @return int
     */
    int miniSpanningTree(int n, int m, vector<vector<int> >& cost) {
        // write code here
        UnionFindSet my_graph(n+1);
        sort(cost.begin(), cost.end(), 
             [](const vector<int> &lhs, const vector<int> &rhs){
                 return lhs[2] < rhs[2];
             });
        int cnt = 0;
        for(auto &i_vec : cost)
            if( my_graph.union_set(i_vec[0], i_vec[1]) )
                cnt += i_vec[2];
        return cnt;
    }
};

C++ 解法, 执行用时: 3ms, 内存消耗: 376KB, 提交时间: 2021-03-28

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 返回最小的花费代价使得这n户人家连接起来
     * @param n int n户人家的村庄
     * @param m int m条路
     * @param cost intvector<vector<>> 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价
     * @return int
     */
    struct Edge{
        int from;
        int to;
        int length;
        bool operator<(const Edge& x){
            return length<x.length;
        }
    };
    Edge edge[10010];
    int height[10010];
    int father[10010];
    void Initial(int n){
        for(int i=1;i<=n;i++){
            height[i]=0;
            father[i]=i;
        }
    }
    int find(int x){
        if(x!=father[x]) x= find(father[x]);
        return x;
    }
    void Union(int x,int y){
        x=find(x);
        y=find(y);
        if(height[x]>height[y]) father[y]=x;
        else if(height[y]>height[x]) father[x]=y;
        else {
            father[y]=x;
            height[x]++;
        }
    }
    int floyd(int m){
        int sum=0;
        sort(edge, edge+m);
        for(int i=0;i<m;i++){
            if(find(edge[i].from)!=find(edge[i].to)){
                Union(edge[i].from, edge[i].to);
                sum+=edge[i].length;
            }
        }
        return sum;
    }
    int miniSpanningTree(int n, int m, vector<vector<int> >& cost) {
        for(int i=0;i<m;i++){
            edge[i].from=cost[i][0];
            edge[i].to=cost[i][1];
            edge[i].length=cost[i][2];
        }
        Initial(n);
        return floyd(m);
    }
};

C++ 解法, 执行用时: 3ms, 内存消耗: 376KB, 提交时间: 2021-03-22

class Solution {
public:
    static bool cmp(vector<int>&x ,vector<int> &y) {
        return x[2]<y[2];
    }
    int find(vector<int> &p,int x) {
        if(p[x] !=x) p[x] = find(p,p[x]);
        return p[x];
    }
    int miniSpanningTree(int n, int m, vector<vector<int> >& cost) {
        // write code here
        vector<int> parent(n+1);
        for(int i=0;i<=n;++i) parent[i] = i;
        sort(cost.begin(),cost.end(),cmp);
        int res=0;
        for(vector<int>&v: cost) {
            int x = v[0],y=v[1],w = v[2];
            int px = find(parent,x),py = find(parent,y);
            if(px!=py) {
                res+=w;
                parent[px] = py;
            }
        }
        return res;
        
    }
};

C++ 解法, 执行用时: 3ms, 内存消耗: 376KB, 提交时间: 2021-03-16

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 返回最小的花费代价使得这n户人家连接起来
     * @param n int n户人家的村庄
     * @param m int m条路
     * @param cost intvector<vector<>> 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价
     * @return int
     */
    class UnionFind{
    private:
        vector<int> v;
    public:
        UnionFind(int n):v(n, -1){}
        int Find(int i){
            return (v[i]==-1)?i:(Find(v[i]));
        }
        void Union(int i, int j){
            int x = Find(i);
            int y = Find(j);
            if (x!=y){
                v[x] = y;
            }
        }
        bool sameset(int i, int j){
            return (Find(i) == Find(j));
        }
    };
    
    int miniSpanningTree(int n, int m, vector<vector<int> >& cost) {
        // write code here
        sort(cost.begin(), cost.end(), 
             [](const vector<int>& a, const vector<int>& b)->bool{
                 return a[2] < b[2];
             });
        UnionFind u(n+1);
        int rtn = 0;
        int tmp = 0;
        for (vector<int>& v : cost){
            int a = u.Find(v[0]);
            int b = u.Find(v[1]);
            if (a != b){
                u.Union(a, b);
                rtn += v[2];
                tmp ++;
                if (tmp == n-1){
                    break;
                }
            }
        }
        return rtn;
    }
};

C++ 解法, 执行用时: 3ms, 内存消耗: 380KB, 提交时间: 2021-03-07

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 返回最小的花费代价使得这n户人家连接起来
     * @param n int n户人家的村庄
     * @param m int m条路
     * @param cost intvector<vector<>> 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价
     * @return int
     */
    struct edge{
        int start;
        int end;
        int cost;
        edge(int s=0,int e=0,int c=0):start(s),end(e),cost(c){
            
        }
    };
    vector<int>parent;
    int find(int val){
        if(parent[val]==-1)
            return val;
        else
            return find(parent[val]);
    }
    int miniSpanningTree(int n, int m, vector<vector<int> >& cost) {
        // write code here
        vector<edge>edges;
        parent.resize(n+1,-1);
        for(int i=0;i<m;i++){
            edges.push_back(edge(cost[i][0],cost[i][1],cost[i][2]));
        }
        sort(edges.begin(),edges.end(),[](edge&left,edge&right){return left.cost<right.cost;});
        int res=0;
        int count=0;
        for(int i=0;i<m;i++){
            auto cur=edges[i];
            int x=find(cur.start);
            int y=find(cur.end);
            if(x!=y){
                ++count;
                res+=cur.cost;
                parent[x]=y;
                if(count==n-1)
                    break;
            }
        }
        return res;
    }
};

上一题