题目
给你一个正整数 n ,表示总共有 n 个城市,城市从 1 到 n 编号。给你一个二维数组 roads ,其中 roads[i] = [ai, bi, distancei] 表示城市 ai 和 bi 之间有一条 双向 道路,道路距离为 distancei 。城市构成的图不一定是连通的。
两个城市之间一条路径的 分数 定义为这条路径中道路的 最小 距离。
城市 1 和城市 n 之间的所有路径的 最小 分数。
注意:
一条路径指的是两个城市之间的道路序列。
一条路径可以 多次 包含同一条道路,你也可以沿着路径多次到达城市 1 和城市 n 。
测试数据保证城市 1 和城市n 之间 至少 有一条路径。
问题解析
这个题目实际上就是连通图分组的问题。根据各个点的连通关系,可以把原始图分成若干个连通图。又因为题目里说“保证城市 1 和城市n 之间 至少 有一条路径”,所以1,n一定在一个连通图里,那么此时这个图里的最短路径就是问题答案。
所以思路到这就比较明确了,可以用并查集的思想,把原始图做分组,然后找到1所在的组,求得最小值。
代码实现
import java.util.*;
class Solution {
public int minScore(int n, int[][] roads) {
UnionFind unionFind = new UnionFind(n);
for(int i=0;i<n;i++){
unionFind.add(i);
}
for(int i=0;i<roads.length;i++){
int [] disArr = roads[i];
int start = disArr[0];
int end = disArr[1];
//各自所属的集合,不是同一个,那就把这俩合并
if(!unionFind.isConnected(start-1,end-1)){
unionFind.merge(start-1,end-1);
}
}
int minDis = 1000000;
for(int i=0;i<roads.length;i++){
int [] disArr = roads[i];
int start = disArr[0];
int end = disArr[1];
int dis = disArr[2];
//只要判断start,end中的一个即可
if(unionFind.isConnected(0,start-1)){
minDis = Math.min(minDis,dis);
}
}
return minDis;
}
}
//并查集类
class UnionFind {
//
private int[] father;
private int size;
public UnionFind(int n){
father = new int[n];
size = 0;
}
//初始化的时候,每个人的父亲是自己
public void add(int x){
father[x] = x;
size ++;
}
//找祖宗,找的过程也会重新赋值
public int findFather(int x){
if(father[x]!=x){
father[x] = findFather(father[x]);
}
return father[x];
}
//把两个集合合并在一起,选出新的父亲
public void merge(int x,int y){
int xFather = findFather(x);
int yFather = findFather(y);
//直接把x合并到y的集合中。也就是把x的祖宗,指向y的祖宗
if(xFather != yFather){
father[xFather] = yFather;
size--;
}
}
//判断祖宗是否一样
public boolean isConnected(int x,int y){
return findFather(x) == findFather(y);
}
}