LeetCode-1135. Connecting Cities With Minimum Cost [C++][Java]

LeetCode-1135. Connecting Cities With Minimum CostLevel up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.https://leetcode.com/problems/connecting-cities-with-minimum-cost/There are N cities numbered from 1 to N.

You are given connections, where each connections[i] = [city1, city2, cost] represents the cost to connect city1 and city2together.  (A connection is bidirectional: connecting city1 and city2 is the same as connecting city2 and city1.)

Return the minimum cost so that for every pair of cities, there exists a path of connections (possibly of length 1) that connects those two cities together.  The cost is the sum of the connection costs used. If the task is impossible, return -1.

Example 1:

Input: N = 3, connections = [[1,2,5],[1,3,6],[2,3,1]]
Output: 6
Explanation: 
Choosing any 2 edges will connect all cities so we choose the minimum 2.

Example 2:

Input: N = 4, connections = [[1,2,3],[3,4,4]]
Output: -1
Explanation: 
There is no way to connect all cities even if all edges are used.

Note:

  1. 1 <= N <= 10000
  2. 1 <= connections.length <= 10000
  3. 1 <= connections[i][0], connections[i][1] <= N
  4. 0 <= connections[i][2] <= 10^5
  5. connections[i][0] != connections[i][1]

【C++】

1. prim

  • 把一个初始顶点的所有边加入优先队列
  • 取出最短的边,把这条边的另一个顶点相关的边加入队列
  • 再取出最小的边,重复下去,直到所有顶点加入过了
struct cmp {
	bool operator()(const pair<int,int>& a, const pair<int,int>& b) const {
		return a.second > b.second;//小顶堆, 距离小的优先
	}
};
class Solution {
public:
    int minimumCost(int N, vector<vector<int>>& connections) {
		vector<bool> vis(N+1, false);
    	vector<vector<pair<int,int>>> edges(N+1,vector<pair<int,int>>());
    	for (auto& c : connections) {
            edges[c[0]].push_back({c[1],c[2]});
            edges[c[1]].push_back({c[0],c[2]});
        }
    	priority_queue<pair<int,int>, vector<pair<int,int>>, cmp> q;
    	int to, distance, total = 0, edge = 0;
        vis[1] = true;
        for (auto& e : edges[1]) {q.push(e);}          
    	while (!q.empty()) {
    		to = q.top().first;
    		distance = q.top().second;
    		q.pop();
    		if(!vis[to]) {
                vis[to] = true;
                total += distance;
                edge++;
                if (edge == N-1) {return total;}
                for (auto& e : edges[to]) {q.push(e);}       
            }
    	}
    	return -1;
    }
};

2. Kruskal

  • 将边的权值排序,小的先遍历,用并查集检查两个顶点是否合并了,没有合并则将该边加入生成树
  • 也可以使用优先队列实现(相当于排序)
class dsu {
	vector<int> f;
public:
	dsu(int n) {
		f.resize(n);
		for(int i = 0; i < n; ++i) {f[i] = i;}
	}
	
    void merge(int a, int b) {
		int fa = find(a);
		int fb = find(b);
		f[fa] = fb;
	}
	
    int find(int a) {
		int origin = a;
		while(a != f[a]) {a = f[a];}
		return f[origin] = f[a];
	}
};

class Solution {
public:
    int minimumCost(int N, vector<vector<int>>& connections) {
    	dsu u(N+1);
    	sort(connections.begin(), connections.end(),[&](auto a, auto b) {
    		return a[2] < b[2];//距离短的边优先
    	});
    	int edge = 0, p1, p2, dis, total = 0;
    	for(int i = 0; i < connections.size(); ++i) {
    		p1 = connections[i][0];
    		p2 = connections[i][1];
    		dis = connections[i][2];
    		if(u.find(p1) != u.find(p2)) {
    			u.merge(p1,p2);
    			edge++;
    			total += dis;
    		}
    		if(edge == N-1) {break;}
    	}
    	return edge == N-1 ? total : -1;
    }
};

【Java】

class Solution {
    public int minimumCost(int N, int[][] connections) {
        Arrays.sort(connections, (a, b) -> a[2] - b[2]);    
        int res = 0;
        UF uf = new UF(N);
        for (int [] connect : connections) {
            if(uf.find(connect[0]) != uf.find(connect[1])) {
                uf.union(connect[0], connect[1]);
                res += connect[2];
            }
            if (uf.count == 1) {
                return res;
            }
        }         
        return -1;
    }
}

class UF{
    int [] parent;
    int [] size;
    int count;

    public UF(int n) {
        parent = new int[n+1];
        size = new int[n+1];
        for (int i = 0; i<=n; i++) {
            parent[i] = i;
            size[i] = 1;
        }      
        this.count = n;
    }
 
    public int find(int i) {
        if (i != parent[i]) {
            parent[i] = find(parent[i]);
        }
        return parent[i];
    }
     
    public void union(int p, int q) {
        int i = find(p);
        int j = find(q);
        if (size[i] > size[j]) {
            parent[j] = i;
            size[i] += size[j];
        } else {
            parent[i] = j;
            size[j] += size[i];
        }         
        this.count--;
     }
}

参考文献

【1】大顶堆升序、小顶堆降序的堆排序(以Java描述为例版本)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贫道绝缘子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值