最小生成树

方法一:克鲁斯卡尔(Kruskal)算法

用来求加权连通图的最小生成树的算法
算法思想:
1、对图的所有边按照权值大小进行排序
2、依次将最小边添加到最小生成树中,需要判断这条边是否构成了回路,如果构成回路则不能加入
针对这两个问题的具体实现细节
1、对图的所有边按照权值大小进行排序即可
2、记录每个顶点在最小生成树中的终点,每次要添加一条边时,判断该边的两个顶点的终点是否重合,如果重合说明存在回路

所需变量:
1、二维数组matrix:保存顶点与顶点之间的边长度
2、一维数组int[] end:保存各个顶点的终点
3、链表result:保存最终的最小生成树
4、还需要把二维数组matrix的边保存到一个类中,做排序,该类可以设置属性变量有两个顶点和边长度

代码

  public int minCostConnectPoints(int[][] points) {
        int n = points.length;
        List<int[]> edge = new ArrayList<>();
        for(int i=0;i<n;++i)
        {
            for(int j=i+1;j<n;++j)
            {
                if(points[i][j]!=0)
                    edge.add(new int[]{i,j,distance(points[i],points[j])});
            }
        }
//        edge.sort(new Comparator<int[]>() {
//            @Override
//            public int compare(int[] o1, int[] o2) {
//                return o1[2]-o2[2];
//            }
//        });
        //排序
        edge.sort((a,b)->a[2]-b[2]);
        //计算是否有回路
        union uf = new union(n);
        int ans = 0;
        int num =1;
        //从大到小遍历边
        for(int[] tmp:edge)
        {
            if(uf.union(tmp[0],tmp[1]))
            {
                ans = ans + tmp[2];
                //如果边总数n了就跳出,为什么这里是++num
            }
        }
        return ans;
    }
    public class union
    {
        int[] father;
        public union(int n)
        {
            //初始化
            this.father = new int[n];
            for(int i=0;i<n;++i)
                father[i] = i;
        }
        //找终点
        public int find(int x)
        {
            while(father[x]!=x)
            {
                x = father[x];
            }
            return x;
        }
        public boolean union(int x,int y)
        {
            int fx = find(x);
            int fy = find(y);
            if(fx!=fy) {
                //更新终点
                father[fx] = fy;
                return true;
            }
            return false;
        }
    }
    public int distance(int[] a,int[] b)
    {
        return Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]);
    }

方法二、prime方法

prime算法和求最短路径的思想很像,是一种贪心算法
1、将图中任意顶点加入最小生成树
2、将该顶点所有的边加入一个边集合
3、从该边集合找到最小边,并把该边的另一顶点加入最小生成树
4、重复步骤二
5、直至所有顶点都加入最小生成树

所需变量:
int[] visited:以为数组,用来判断顶点是否加入最小生成树了
相当于邻接表,数组链表List<int[]>[] graph:保存每个顶点的边和距离
queue<int[]>:小根堆,用来维护边集合,每次弹出来的都是最小边

代码:

//普利姆算法
public class minTree {
    boolean[]  visited;
    PriorityQueue<int[]> queue ;
    List<int[]>[] graph;
    public int minCostConnectPoints(int[][] points)
    {
        graph = buildGraph(points);
        visited = new boolean[points.length];
        queue = new PriorityQueue<>((o1, o2) -> o1[2]-o2[2]);
        visited[0] = true;
        cut(0);
        int minlen = 0;
        while(!queue.isEmpty())
        {
            int[] node = queue.poll();
            if(visited[node[1]])
                continue;
            minlen = minlen+node[2];
            visited[node[1]] = true;
            cut(node[1]);
        }
        return minlen;
    }
    public void cut(int start)
    {
        for(int[] tmp:graph[start])
        {
            int j = tmp[1];
            if(visited[j])
                continue;
            queue.offer(new int[]{start,j,tmp[2]});
        }
    }
    public List<int[]>[] buildGraph(int[][] points)
    {
        List<int[]>[] graph = new LinkedList[points.length];
        for(int i =0;i<points.length;++i)
        {
            graph[i] = new LinkedList<>();
        }
        for(int i=0;i<points.length;++i)
        {
            for(int j=i+1;j<points.length;++j)
            {
                graph[i].add(new int[]{i,j,distance(points[i],points[j])});
                graph[j].add(new int[]{j,i,distance(points[i],points[j])});
            }
        }
        return graph;
    }
    public int distance(int[] a, int[] b)
    {
        return Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]);
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值