面试常规算法复习(最小生成树)

两种常规的算法。

package com.company;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;


class Edge {
    int a, b, w;
    Edge(int a, int b, int w){
        this.a = a;
        this.b = b;
        this.w = w;
    }
}

public class Main {
    public static void main(String[] args) {
        int w[][] = new int[1005][1005];
        int INF = 0x3f3f3f3f;
//        System.out.println(INF);
        int n, m;
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();

        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= n; j++)
                if (i != j)w[i][j] = INF;
                else w[i][j] = 0;
        }
        for (int i = 1; i <= m; i++){
            int u, v, W;
            u = in.nextInt();
            v = in.nextInt();
            W = in.nextInt();
            w[u][v] = Math.min(w[u][v], W);
            w[v][u] = Math.min(w[v][u], W);
        }
//        int s = in.nextInt();
//        int e = in.nextInt();
//        kruskal(n, w);
        prime(n, w);
    }

    public static int finds(int n, int f[]){
        return f[n] == n?n:(f[n] = finds(f[n], f));
    }


    //将所有的边排序,从最小的边开始,将两点加入集合,如果在同一集合那么就不记录
    //集合通过并查集维护
    public static void kruskal(int n, int w[][]){
        int INF = 0x3f3f3f3f;
        Comparator<Edge> comparator = new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.w-o2.w;
            }
        };
        Queue<Edge> q = new PriorityQueue<Edge>(comparator);
        for (int i = 1; i <= n; i++){
            for (int j = i+1; j <= n; j++){
                if (w[i][j] != INF){
                    q.add(new Edge(i, j, w[i][j]));
                }
            }
        }
        int f[] = new int[1005];
        for (int i = 1; i <= n; i++){
            f[i] = i;
        }
        int sum = 0;
        while (!q.isEmpty()){
            Edge x = q.poll();
            int a = finds(x.a, f);
            int b = finds(x.b, f);
            if (a != b){
                f[a] = b;
                sum += x.w;
            }
        }
        System.out.println(sum);
    }
    //思想类似与迪杰斯特拉算法。。。
    //选择一个开始点,选择与开始点最短距离的点,将其连接记录,后面重复上次操作就可以了。
    //注意在那个距离更新不是松弛操作。

    public static void prime(int n, int w[][]){
        int d[] = new int[1005];
        boolean vis[] = new boolean[1005];
        int INF = 0x3f3f3f3f;
        for(int i = 1; i <= n; i++)d[i] = (i==1)?0:INF;
        int sum = 0;
        for(int i = 1; i <= n; i++){
            int x=1, m=INF;
            for(int j = 1; j <= n; j++){
                if(!vis[j] && m > d[j]){
                    x = j;
                    m = d[j];
                }
            }
            vis[x] = true;
            sum += m;
//            System.out.println(m);
            for (int j = 1; j <= n; j++){
                if (!vis[j])d[j] = Math.min(d[j], w[j][x]);
            }
        }
        System.out.println(sum);
    }


}

posted @ 2019-12-05 12:18  huas_lqy  阅读(163)  评论(0编辑  收藏  举报