并查集+排序 的最长木材问题 求最小生成树的最大边权值问题
2018-03-22 19:36
302 查看
亮亮解出了卷轴隐藏的秘密,来到了一片沼泽地。这里有很多空地,而面试直通卡可能埋在任意一块空地中,好在亮亮发现了一堆木材,他可以将木材铺在两个空地之间的沼泽地上。因为亮亮不知道面试直通卡具体在哪一块空地中,所以必须要保证任意一块空地对于亮亮来说是可以抵达的。 “怎么还有鳄鱼!没办法,看来有些空地不能直接到达了。” 亮亮虽然没有洁癖,但是沼泽地实在太臭了,所以亮亮不会循环利用木材。而且木材不能拼接在一起使用,所以亮亮必须要知道在耗费木材最少的情况下,最长的那根木材至少需要多长。
链接:https://www.nowcoder.com/questionTerminal/59aff3b7a9094432893302c9ee7794e8
来源:牛客网
[b]输入描述:[/b]
利用并查集的方法,再多加一个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;
}
}
链接: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;
}
}
相关文章推荐
- 二叉树中最大最小权值节点距离问题
- POJ 2485 Highways(最小生成树,树的最大权值边)
- (prim算法题型一)求最小生成树的权值和、路径、边值的最小和最大值。
- 最小生成树 prime算法 求权值最大的边
- POJ3723 Conscription , 最大权森林问题 ->最小生成树问题
- Prim最小生成树(求,生成树中权值的和,最大权值,最小权值) 参考poj1258 2485
- 二叉树求最大最小权值问题的面试题
- poj 2485 Highways(最小生成树中求最大权值)
- (hruscal12.3.3)POJ 3522 Slim Span(求解一个生成树使得该树中的最大边权值和最小边权值之差最小)
- * 问题描述:输入10个整数,将其中最小的数与第一个数对换,把最大的数与最后一个数对换。写三个函数; ①输入10个数;②进行处理;③输出10个数。
- HDU 1879(最小生成树问题,Prim)
- Java_int最大值加一和最小值减一问题
- 1090. Highways(用并查集找出最小生成树,输出最小生成树中最长的边
- UESTC 1635 最大最小生成树
- HDOJ 1875 畅通工程再续---最小生成树问题
- 带权图的最小生成树问题
- 算法java实现--贪心算法--最小生成树问题--Prim算法
- POJ-1797Heavy Transportation (最小生成树问题)
- ALGO-6 安慰奶牛 — 最小生成树的引申问题(java)
- hrbustOJ 最小生成树问题(kruskal)