数据结构与算法 图论(三)最小生成树

Kruskal算法

对边排序,选出n-1条路径最短的边。即得到一个最小生成树。
在这里插入图片描述
在选边过程中,需要判断,两点是否已经连通。可以使用dfs或bfs但是效率很低,这里使用并查集来判断图中的两点是否已经连通.。

import java.util.Scanner;

public class zuixiaoshengchengshu {
    static class edge{
        int u;
        int v;
        int w;
    }
    static edge [] e;
    static int [] f;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int count=0,sum=0;
        int n = scan.nextInt();
        int m = scan.nextInt();
        e = new edge[m+1];
        f = new int[n+1];
        for (int i = 1; i <= m; i++) {
            e[i] = new edge();
            e[i].u = scan.nextInt();
            e[i].v = scan.nextInt();
            e[i].w = scan.nextInt();
        }

        quickSort(1,m);
        init(n);

        for (int i = 1; i <= m; i++) {
            if (merge(e[i].u,e[i].v) != 0){
                count++;
                sum+=e[i].w;
            }
            if (count == n-1)
                break;
        }

        System.out.print(sum);
    }

    private static void quickSort(int left,int right) {
        int i,j,temp;
        edge t;
        if (left > right)   //'='的取舍
            return;
        temp = e[left].w;
        i = left;
        j = right;
        while (i != j){
            while (e[j].w >= temp && i < j)
                j--;
            while (e[i].w <= temp && i < j)
                i++;
            if (i < j){
                t = e[i];
                e[i] = e[j];
                e[j] = t;
            }
        }
        //基准数归位
        t = e[left];
        e[left] = e[i];
        e[i] = t;

        quickSort(left,i-1);
        quickSort(i+1,right);
    }

    //合并两子集的函数
    private static int merge(int v, int u) {
        int t1 = getf(v);
        int t2 = getf(u);
        if (t1 != t2){
            //靠左原则,左边变成右边的子集,即把右边的集合,作为左边集合的子集和
            f[t2] = t1;
            return 1;
        }
        return 0;
    }

    //找爹的函数,不停的去找爹,直到找到祖宗为止,其实就是找最高领导人
    private static int getf(int v){
        if (f[v] == v)
            return v;
        else {
            f[v]=getf(f[v]);
            return f[v];
        }
    }

    private static void init(int n) {
        for (int i = 1; i <= n; i++) {
            f[i] = i;
        }
    }

}

在这里插入图片描述

Prim算法

要用n-1条边将n个点连接起来,那么每个点都必须至少有一条边与它相连。
在这里插入图片描述

import java.util.Scanner;
public class Prim {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int [][] e = new int[7][7];
        int [] dis = new int[7];
        int [] book = new int[7];
        int inf = Integer.MAX_VALUE;
        int count=0,sum=0;
        int n = scan.nextInt();
        int m = scan.nextInt();

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (i == j) e[i][j]=0;
                else e[i][j]=inf;
            }
        }

        for (int i = 1; i <= m; i++) {
            int t1 = scan.nextInt();
            int t2 = scan.nextInt();
            int t3 = scan.nextInt();
            e[t1][t2] = t3;
            e[t2][t1] = t3;
        }

        //初始化dis数组,这里是1号顶点到各个顶点的距离,因为当前是生成树中使用1号顶点
        for (int i = 1; i <= n; i++) {
            dis[i] = e[1][i];
        }

        //Prim核心
        book[1]=1;
        count++;
        while (count < n){
            int min = inf,j = 0;
            for (int i = 1; i <= n; i++) {
                if (book[i] == 0 && dis[i] < min){
                    min = dis[i];j=i;
                }
            }

            //为下一次找离生成树最近的点做准备
            book[j]=1;count++;sum+=dis[j];

            for (int i = 1; i <= n; i++) {
            //当点还没有加入生成树,就更新
                //注意:记录的是离生成树最近的点而不是离某一点最近的点,但是j只能最新加入到生成树中点。
                if (book[i] == 0 && dis[i] > e[j][i])
                    dis[i] = e[j][i];
            }
        }

        System.out.println(sum);
    }
}

在这里插入图片描述

posted @ 2021-04-07 17:09  木有呂朋友  阅读(41)  评论(0编辑  收藏  举报