【Lintcode】783. Minimum Risk Path(配数学证明)

题目地址:

https://www.lintcode.com/problem/minimum-risk-path/description

给定 m m m条无向边,每条边给出两个端点和权值(权值都是正的)。一条路径的危险值定义为其所有边的权值的最大值。给定一个顶点 n n n,问从顶点 0 0 0 n n n的所有路径中危险值最小的那个路径的危险值是多少。

思路是用最小生成树的Kruskal算法。先将边按照权值排序,然后一条一条地将边加上去,一旦发现 0 0 0 n n n连通了之后,正在加的那条边的权值就是答案(判断连通需要用到并查集)。

算法正确性证明:
正确性还是蛮显然的。显然最小危险值不会大于算法求得的值,因为Kruskal算法已经算出了一条路径;而最小危险值也不会小于算法求得的值,因为只靠那些权值更小的边是无法构造出连通图的。所以算法求得的值即为所求。

代码如下:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Solution {
    
    class UnionFind {
        private Map<Integer, Integer> parent;
    
        public UnionFind() {
            parent = new HashMap<>();
        }
    
        void add(int x) {
            parent.putIfAbsent(x, x);
        }
        
        int find(int x) {
            if (x != parent.get(x)) {
                parent.put(x, find(parent.get(x)));
            }
            
            return parent.get(x);
        }
        
        // 如果x和y已经在一个集合里了就返回false,否则union它们所在集合并返回true
        boolean union(int x, int y) {
            int px = find(x), py = find(y);
            if (px == py) {
                return false;
            }
            
            parent.put(px, py);
            return true;
        }
    }
    
    class Edge {
    	// 把边的权值和它在原数组中的下标记录下来
        int weight, idx;
        
        public Edge(int weight, int idx) {
            this.weight = weight;
            this.idx = idx;
        }
    }
    
    /**
     * @param n: maximum index of position.
     * @param m: the number of undirected edges.
     * @param x:
     * @param y:
     * @param w:
     * @return: return the minimum risk value.
     */
    public int getMinRiskValue(int n, int m, int[] x, int[] y, int[] w) {
        // Write your code here.
        UnionFind uf = new UnionFind();
        
        Edge[] edges = new Edge[m];
        for (int i = 0; i < m; i++) {
            edges[i] = new Edge(w[i], i);
            uf.add(x[i]);
            uf.add(y[i]);
        }
        
        // 按照权值排序
        Arrays.sort(edges, (e1, e2) -> Integer.compare(e1.weight, e2.weight));
    
        for (int i = 0; i < edges.length; i++) {
            int idx = edges[i].idx;
            // 把这条边加在图中
            uf.union(x[idx], y[idx]);
            // 一旦发现0和n连通了,就返回边的权值
            if (uf.find(0) == uf.find(n)) {
                return edges[i].weight;
            }
        }
        
        return -1;
    }
}

时间复杂度 O ( w log ⁡ w ) O(w\log w) O(wlogw),空间 O ( V + w ) O(V+w) O(V+w)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值