最小生成树(kruskal,prim)

一个连通图的最小连通子图(再去掉一条边就不是连通的),一般针对于带权图,即在原图当中边的权值最小的一棵生成树

特性

  • 一个连通图可以有很多棵生成树
  • 不存在环

Kruskal算法(贪心)

从局部最优到整体最优,不断选择当前最优的。从边出发

  1. 先把所有的边按降序排列
  2. 从小到大添加,遇到环跳过(采用并查集判断)

浅谈贪心算法与动态规划

贪心算法是自顶向下,当我们想要要求解的问题可以通过局部最优的选择来达到,不断迭代,最优子结构。贪心不能保证最后的解一定是最佳的,只能求解一下满足某一些约定条件的可行解

动态规划是自底向上,也是不断拆解子问题但是目标明确

public class Kruskal {
    public void kruskal(MyGraph myGraph){
        int edgCount = 0;
        //使用简单的冒泡排序对边集数组按距离从小到大排序
        for (int i = 0; i < myGraph.eNums - 1; i++) {
            for (int j = 0; j < myGraph.eNums - i - 1; j++) {
                if(myGraph.edges[j].weight>myGraph.edges[j+1].weight){
                    int temp = myGraph.edges[j].weight;
                    myGraph.edges[j].weight = myGraph.edges[j+1].weight;
                    myGraph.edges[j+1].weight = temp;
                }
            }
        }
        //初始化
        int[] parent = new int[myGraph.vNums];
        for (int i = 0; i < myGraph.vNums; i++) {
            parent[i] = i;
        }
        for (int i = 0; i < myGraph.eNums; i++) {
            int begin = find(parent,parent[myGraph.edges[i].begin]);
            int end = find(parent,parent[myGraph.edges[i].end]);
            if(begin != end){
                //如果两个结点的根结点不一样说明不会形成环路
                parent[begin] = end;
                edgCount++;
                if(edgCount == myGraph.eNums - 1){
                    break;
                }
            }
        }

    }

    /**
     * 并查集思想查找根结点
     * @param parent 父结点数组
     * @param index 查找的结点下标
     * @return 根结点
     */
    public int find(int[] parent,int index){
        //直到找到根结点
        while(parent[index]!=index){
            index = parent[index];
        }
        return index;
    }
}

Prim算法

普⾥姆算法在找最⼩⽣成树时,将顶点分为两类,⼀类是在查找的过程中已经包含在⽣成树

中的顶点,剩下的为不在集合里的。

  1. 选初始结点,将它移到集合里
  2. 找出与集合里顶点相连接的权值最小的顶点,将其加入集合
  3. 重复步骤2
public class Prim {
    public void prim(MGraph mGraph){
        //保存相关顶点的下标
        int[] adjvex = new int[mGraph.vNums];
        //保存当前集合到各个顶点的最小权值
        int[] lowcost = new int[mGraph.vNums];
        //将v0加入集合
        lowcost[0] = 0;
        for (int i =1;i< mGraph.vNums;i++){
            adjvex[i] = 0;//初始化
            lowcost[i] = mGraph.arcs[0][i];//初始集合到各个顶点的最小权值即v0到各个顶点的权值
        }
        //构造最小生成树
        for (int i = 0; i < mGraph.vNums; i++) {
            int minWeight = Integer.MAX_VALUE;//最小的权值
            int j = 1;
            int k = 0;//最小的权值结点下标
            //遍历所有的结点
            while(j<mGraph.vNums){
                //找到集合外相邻边权值最小的一条
                if(lowcost[j]!=0&&lowcost[j]<minWeight){
                    minWeight = lowcost[j];
                    //将发现的最小权值的下标存入k,以便使用
                    k = j;
                }
                j++;
            }
            System.out.println(" " + adjvex[k] + k);//连接当前最小权值结点的相关顶点
            //加入新的结点后
            lowcost[k] = 0;
            // 更新一遍集合相邻最小权值
            for (j = 1;j<mGraph.vNums;j++){
                if(lowcost[j]!=0&&mGraph.arcs[k][j]<lowcost[j]){
                    lowcost[j] = mGraph.arcs[k][j];
                    adjvex[j] = k;//连接集合相邻最小权值结点的结点
                }
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值