您的位置:首页 > 其它

并查集+排序 的最长木材问题 求最小生成树的最大边权值问题

2018-03-22 19:36 302 查看
亮亮解出了卷轴隐藏的秘密,来到了一片沼泽地。这里有很多空地,而面试直通卡可能埋在任意一块空地中,好在亮亮发现了一堆木材,他可以将木材铺在两个空地之间的沼泽地上。因为亮亮不知道面试直通卡具体在哪一块空地中,所以必须要保证任意一块空地对于亮亮来说是可以抵达的。 “怎么还有鳄鱼!没办法,看来有些空地不能直接到达了。” 亮亮虽然没有洁癖,但是沼泽地实在太臭了,所以亮亮不会循环利用木材。而且木材不能拼接在一起使用,所以亮亮必须要知道在耗费木材最少的情况下,最长的那根木材至少需要多长。
链接:https://www.nowcoder.com/questionTerminal/59aff3b7a9094432893302c9ee7794e8
来源:牛客网

[b]输入描述:[/b]
第一行包含两个整数N(1≤N≤10000),M(1≤M≤1000000)。N表示公有N块空地。
接下来M行,每行包含三个整数P(1≤P≤N),Q(1≤Q≤N),K代表P,Q两个间没有鳄鱼,需要耗费K的木材。
[b]输出描述:[/b]
一个整数,即耗费木材最少的情况下,最长的那根木材长度。
示例1

输入

4 3
1 2 1
2 3 1
3 4 2

输出

2
可以参考我博客里的另一篇 并查集 的文章。【https://mp.csdn.net/postedit/79616869】
利用并查集的方法,再多加一个Edge排序方法。便可以解决这个问题。
【写的时候,基础不牢固,多次卡在 Arrays对象排序问题,重点理解father[ ]的生成】import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {

public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){//while只用了一次吧
String[] mn = scanner.nextLine().split(" ");
int n = Integer.parseInt(mn[0]);
int m = Integer.parseInt(mn[1]);
//接下来读取每行的信息,存储在String mn中,并且用空格分隔开
Edge[] edges = new Edge[m];
for(int i = 0;i < m;i++){
//提前记录下一行的值
String[] str = scanner.nextLine(). split(" ");//读取的循环在这里
int x = Integer.parseInt(str[0]);
int y = Integer.parseInt(str[1]);
int k = Integer.parseInt(str[2]);
edges[i] = new Edge(x,y,k);
}
System.out.print(max_k(edges,n,m));

}
scanner.close();
}

//n是点数,m是边数,edges是边的集合
public static int max_k(Edge[] edges,int n,int m){
int res = 0;//返回最大值
int[] father = new int[n+1];
primaryset(father,n);//father初始化,暂且认为所有节点的父点都是自己
Arrays.sort(edges,new BykComparator());
/*Arrays.sort(edges, new Comparator<Edge>() {
@Override
public int compare(Edge e1, Edge e2) {
return e1.k - e2.k;
}
});*/
for(int i = 0;i < m;i++){
int fx = find(father,edges[i].x);
int fy = find(father,edges[i].y);
if(fx != fy ){ //fx和fy如果没有x->y的边的话,目前不再一个连通分支中,那么加上这条边
if(res < edges[i].k)
res = edges[i].k;
mix(father,fx,fy);//对于有边连接的两个点,mix一下,相当于更新father的过程
}
}
return res;
}

//初始化 father[]数组
public static void primaryset(int[] father,int n){
for(int i = 0;i <= n;i++)
father[i] = i;
}
public static int find(int[] father,int x){
int r = x;//复制当前点x,找x的父点,只有father[i]==i时,才找到这个族的根节点
while(father[r] != r){
r = father[r];
}
//路径压缩,便于后来的直接查询
int i= x;
while(i != r){
int temp = father[i];
father[i] = r;
i = temp;
}
return r;//在father数组中找到x的root节点bing返回root,同时执行了路径压缩
}
public static void mix(int[] father,int root1,int root2){
if(root1 < root2){
father[root2] = root1;//对两个族的root点,较小的一个作为较大点的father
}else{
father[root1] = root2;
}
}
}
class Edge{
public int x;
public int y;//边的起点终点
public int k;//存储边权
public Edge(int x,int y,int k){
this.x = x;
this.y = y;
this.k = k;
}
}
class BykComparator implements Comparator{
public final int compare(Object e1,Object e2){
if(((Edge)e1).k > ((Edge)e2).k )
return 1;
else if(((Edge)e1).k == ((Edge)e2).k )
return 0;
else
return -1;

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: