java并查集实现krusual算法【模板】—洛谷p3366

krusual算法实现最小生成树,其实是并查集的应用,通过对每个点用并查集组合就可以获得一棵最小生成树。
以洛谷的p3366为例子:
题目:
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。

输入格式
第一行包含两个整数 N,MN,M,表示该图共有 NN 个结点和 MM 条无向边。

接下来 MM 行每行包含三个整数 Xi,Yi,ZiX 表示有一条长度为 Zi的无向边连接结点 Xi,Yi。

输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz。

这道题,如果用collection进行排序的话会有一点小细节,如果没注意就没有AC,有3个测试点是通过不了的。

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class p3366_model {
    static int[] id;
    static int[] size;
    public static void main(String[] args) throws Exception{
    //测试用的代码,一开始并不知道bug在哪老是re,控制台输入大规模数据读不全,直接用BuffereReader读文件测试
        File f = new File("P3366_2.in");
        BufferedReader reader = new BufferedReader(new FileReader(f));
//        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n,m;
        String[] sb = reader.readLine().split(" ");
        n=Integer.parseInt(sb[0]);
        m=Integer.parseInt(sb[1]);
        init(n);
        List<graph_edge1> l = new ArrayList<>(M);
        for(int i=0;i<m;i++){
            String[] sa = reader.readLine().split(" ");
            int a = Integer.parseInt(sa[0]);
            int b = Integer.parseInt(sa[1]);
            int c = Integer.parseInt(sa[2]);
            graph_edge1 g = new graph_edge1(a,b,c);
            l.add(g);
        }
//        l.stream().sorted();
        Collections.sort(l);
        int res =0;
        int chance = 0;
        for(graph_edge1 g:l){
            if(find(g.begin)!=find(g.end)){
                union(g.begin,g.end);
                res+=g.weight;
                chance++;
            }
        }
        if(chance<n-1) System.out.println("orz");
        else System.out.println(res);

    }
    //接下来三个函数是并查集初始化模板
    public static void init(int n){
        for(int i=1;i<=n;i++){
            id[i] = i;
        }
    }
    public static int find(int x){
        while(x != id[x]) x=id[id[x]];
        return x;
    }
    public static void union(int x ,int y){
        x=find(x);
        y=find(y);
        if(x==y) return;
        id[x] = y;
    }
}
//创建每个边的对象,因为要用Collections.sort()对list排序,所以要调用接口Comparable
class graph_edge1 implements Comparable<graph_edge1>{
    int begin;
    int end;
    int weight;
    public graph_edge1(int a,int b,int c){
        this.begin = a;
        this.end = b;
        this.weight = c;
    }
    /*接下来就是一直bug的地方,一开始我只写了小于的情况,并没有写等于,return0,一般来说是没有问题的,但是当数据量过大,影响排序时,就会报错:java.lang.IllegalArgumentException: Comparison method violates its general contract!  
at java.util.TimSort.mergeHi(TimSort.java:868)  
at java.util.TimSort.mergeAt(TimSort.java:485)  
at java.util.TimSort.mergeCollapse(TimSort.java:408)  
at java.util.TimSort.sort(TimSort.java:214)  
at java.util.TimSort.sort(TimSort.java:173)  
at java.util.Arrays.sort(Arrays.java:659) */
    @Override
    public int compareTo(graph_edge1 o) {
        if( o.weight < this.weight) return 1;
        if( o.weight == this.weight) return 0;
        return -1;
    }
}

细节很重要。

你可能感兴趣的:(java算法,算法,java)