今天更新这篇文章超级激动,因为我会最小生成树的算法了(其实昨天就开始研究了,只是昨天参加牛客网的算法比赛,结果又被虐了,好难过~)

最小生成树的算法,其实学了数据结构就会有一定的基础,Kruskal算法是贪婪法的一种,一直在所有边中选择最小边(当然不能形成环,因为最小生成树是没有环的)。首先遇到的问题就是如何表示这个图,想用邻接矩阵还是关联矩阵。但是这两种矩阵都要输入好多,感觉太浪费空间了。于是,我自己定义了一个类,是边的类。只要一个图的每一条边都关联两个点,两个端点。于是这个类中包括一个关联点的数组,是否被选择,以及边的权值。另外就是这个边的代号,以a,b,c,d...来表示,顶点是int类型,以1,2,3,4...来表示。接下来来看实际的题目吧。

1.问题描述:

    如下图,求图的最小生成树,把边选出来,并且求出最小生成树的权值

    每条边的权值如下:

     a -------------4

     b--------------6

     c--------------4

     d--------------2

     e--------------3

     f---------------1

     g--------------2

     h--------------3

     i---------------4

     j---------------1

     k--------------2

由图利用Kruskal算法不难得出最小生成树所选的边是: f  j  g  d  h  c   / f  j  g  d  h  c....

2.输入:请输入这个图有几条边和顶点数:(11表示边条数,7表示顶点个数) ,接下来3个数,分别为边的权值,边和哪两个点关联
    11 7 
    4 1 2
    6 2 4
    4 2 3
    2 1 4
    3 1 5
    1 4 5
    2 4 6
    3 3 6
    4 5 6
    1 5 7
    2 6 7

3.输出:

    选的边为: f j g d h c
    权值是:13
4.算法思想:

    输入完了之后用一个排序方法,将树的权值从小到大进行排序,保存在Bian[]这个数组中。接下来再从小到大进行选择,判断是否不在同一个连通分量和没有被选择。判断不在一个连通分量很关键。这个思想,我昨天想了好久,开始是想选的边不能形成圈,但发现这样也太难判断了,该怎么看是否形成圈呢?然后就各种百度,查资料,然后发现只要不在同一个联通分量就可以了。比如假如上图:我边a权值是1,边j权值是1,如果不在同一个连通分量,那么还是可以选择的。化为计算机语言,也就是我把已经选择了的边的顶点保存在一个顶点数组里面,如果我接下来要添加的边的两个端点都已经在在这个数组里面,那么就不能选了,如果有一个在,一个不在,或者两个都不在,就可以选。仔细想想是不是这个道理呢?但是我这样做之后发现程序总是少选1条边,原来,选到只剩最后一条边的时候,是可能会两个端点都在数组里的(当然有些图也不会),于是在最后一条边时需要另外判断了。如果是最后一条边,并且两个点都在的话,那就选这条边,else if 继续前面那种选法就可以。

5.代码示例:

import java.util.Scanner;

class Edge{
    int v; //边的权值
    int[] ConnectPoint = new int[2];  //边所连接的点
    int isSelect; //是否被选择,1表示被选,0表示没有被选
    char No; //图的编号,a,b,c,d...在创建图的时候初始化的
}

public class 最小生成树2 {
    public static void main(String[] args) {
        Scanner scn = new Scanner(System.in);
        System.out.println("请输入图有几条边和几个点:");
        int n = scn.nextInt();  //保存边数
        int m = scn.nextInt(); //保存点数
        Edge edge[] = new Edge[n];
        for(int i=0;i<n;i++){
            edge[i] = new Edge();  //创建出真实的边出来
            edge[i].v = scn.nextInt();
            edge[i].ConnectPoint[0] = scn.nextInt();
            edge[i].ConnectPoint[1] = scn.nextInt();
            edge[i].No = (char) ('a' + i);
        }
        
        //输入完了之后,将这些边按权值进行排序
        sort(edge);
        
        //定义一个点的数组,来存放已经选择的边的关联顶点编号
        int hasSelectPoint[] = new int[2*m];  //因为每条边都有关联两个顶点,选择的边存放进来可能会存放两次
        //初始化,这个数组开始全部存0,都没有被选择
        for(int i=0;i<hasSelectPoint.length;i++){
            hasSelectPoint[i] = 0;
        }
        
        //权值排序完成之后就开始选边
        int j=0;
        int step = 1;//选的边数,开始选第一条边
        for(int i=0;i<n;i++){
            //最小生成树要选的边数等于顶点数-1,那么开始要选m-1最后一条边时这样选。再break退出
            if(step == m-1 && allInSelectPoint(edge[i],hasSelectPoint)){ //最后一条边了
                    edge[i].isSelect = 1;//直接选择
                    break;
            }else if(edge[i].isSelect ==0 && !allInSelectPoint(edge[i],hasSelectPoint)){ //如果边没有被选,并且这条边的两个顶点不同时在顶点的数组里
                    edge[i].isSelect = 1;
                    hasSelectPoint[j] = edge[i].ConnectPoint[0];
                    j++;
                    hasSelectPoint[j] = edge[i].ConnectPoint[1];
                    j++;
                    step++; //开始选第二条边
            }
        }
        
        //打印所选的边
        int sum = 0; // 计算权值
        System.out.print("所选的边为:");
        for(int i=0;i<n;i++){
            if(edge[i].isSelect==1){
                sum = sum + edge[i].v;
                System.out.print(edge[i].No + " ");
            }
        }
        System.out.println();
        System.out.println("权值为: " + sum);
    }

    private static boolean allInSelectPoint(Edge edge, int[] hasSelectPoint) {
        int flag1 = 0;
        int flag2 = 0;//这两个变量是分别看边的两个端点在不在存放已经选择点的数组里面
        for(int i=0;i<hasSelectPoint.length;i++){
            if(edge.ConnectPoint[0] ==hasSelectPoint[i]){
                flag1 = 1;
            }
            if(edge.ConnectPoint[1] ==hasSelectPoint[i]){
                flag2 = 1;
            }
        }
        if(flag1 ==1 && flag2 ==1){  //两个点都在
            return true;
        }else {  //都不在或者有一个点不在
            return false;
        }
    }

    //将权值进行交换
    private static void sort(Edge[] edge) {
        Edge tempEdge = null;
        for(int i=0;i<edge.length;i++){
            for(int j=i+1;j<edge.length;j++){
                if(edge[j].v<edge[i].v){
                    tempEdge = edge[i];
                    edge[i] = edge[j];
                    edge[j] = tempEdge;
                }
            }
        }
    }
}

java用Kruskal实现最小生成树的更多相关文章

  1. java实现Kruskal算法

    1 问题描述 何为Kruskal算法? 该算法功能:求取加权连通图的最小生成树.假设加权连通图有n个顶点,那么其最小生成树有且仅有n - 1条边. 该算法核心思想:从给定加权连通图中,选择当前未被选择 ...

  2. Prim和Kruskal求最小生成树

    Prim: 算法步骤: 1.任意结点开始(不妨设为v1)构造最小生成树: 2.首先把这个结点(出发点)包括进生成树里, 3.然后在那些其一个端点已在生成树里.另一端点还未在生成树里的所有边中找出权最小 ...

  3. Kruskal算法-最小生成树

    2017-07-26  10:32:07 writer:pprp Kruskal算法是根据边的加权值以递增的方式,一次找出加权值最低的边来建最小生成树:并且每次添加的边不能造成生成树有回路,直到找到N ...

  4. POJ1679 The Unique MST(Kruskal)(最小生成树的唯一性)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 27141   Accepted: 9712 D ...

  5. BZOJ 1626 [Usaco2007 Dec]Building Roads 修建道路:kruskal(最小生成树)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1626 题意: 有n个农场,坐标为(x[i],y[i]). 有m条原先就修好的路,连接农场( ...

  6. ZOJ 1586 QS Network Kruskal求最小生成树

    QS Network Sunny Cup 2003 - Preliminary Round April 20th, 12:00 - 17:00 Problem E: QS Network In the ...

  7. 图——图的Kruskal法最小生成树实现

    1,最小生成树的特征: 1,选取的边是图中权值较小的边: 2,所有边连接后不构成回路: 2,prim 算法是以顶点为核心的,最下生成树最大的特征是边,但 prim 算法非要以顶点为核心来进行,有些复杂 ...

  8. Codeforces 609E (Kruskal求最小生成树+树上倍增求LCA)

    题面 传送门 题目大意: 给定一个无向连通带权图G,对于每条边(u,v,w)" role="presentation" style="position: rel ...

  9. POJ-2349(kruskal算法+最小生成树中最大边的长度)

    Arctic POJ-2349 这题是最小生成树的变形题目.题目的意思是已经有s个卫星频道,这几个卫星频道可以构成一部分的网络,而且不用费用,剩下的需要靠d的卫星接收器.题目要求的就是最小生成树中,最 ...

随机推荐

  1. NOIP 2017 day 1 游记

    心情非常复杂.大概就是我问到的所有人都A掉了T1那样. 的确没有按套路出牌,今年T1不是大模拟,反倒是T2. ……已经不想再提到今天的T1了.如果真的要我说,我只能说 我再次学了一整年的OI,结果栽到 ...

  2. UOJ #207. 共价大爷游长沙 [lct 异或]

    #207. 共价大爷游长沙 题意:一棵树,支持加边删边,加入点对,删除点对,询问所有点对是否经过一条边 一开始一直想在边权上做文章,或者从连通分量角度考虑,比较接近正解了,但是没想到给点对分配权值所以 ...

  3. django-rest-framework快速入门

    前言:第一次接触django-rest-framework是在实习的时候.当时也不懂,看到视图用类方法写的感觉很牛逼的样子.因为官网是英文的,这对我的学习还是有一点的阻力的,所以当时也没怎么学.真是太 ...

  4. 模拟器配置使用Fildder进行抓包,包含Https+证书

    1.首先,百度检索.参考别人的,大致上都是到安装证书就失败了.我后面只说几个关键点. 2.安装证书,必须设置屏幕密码.我最开始使用把cef拷贝到,手机结果出现bug,安装不了.后来采用了在手机内部访问 ...

  5. php获取今日开始时间戳和结束时间戳

    1.php获取今日开始时间戳和结束时间戳  $beginToday=mktime(0,0,0,date('m'),date('d'),date('Y'));$endToday=mktime(0,0,0 ...

  6. Ubuntu 配置FTP服务器

    第三方的文件传输软件用着很不爽,想着自己搭建一个FTP来干活. 首先检查是否已经安装了FTP,输入命令: vsftpd -v  可以查看版本,如果没有安装,无法执行. 安装FTP p.p1 { mar ...

  7. 借助Maven入手Spring Boot第一个程序

    目前网上有不少Spring Boot的入门文章,都很有帮助,本人最近在深入学习Spring Cloud,在搭建第一个Hello World程序时,感觉对于新手而言,介绍文章怎么详细都不为过,因为其中坑 ...

  8. 几种优化ajax的执行速度的方法

    1.尽量使用局部的变量,而不使用全局变量: 2.优化for循环 3.尽量少用eval,每次使用eval都需要消耗大量的时间: 4.将DOM节点放在文档上. 5.尽量减少点好(.)操作符号的使用

  9. Pandoc将markdown转换为word

    markdown转换为word的指令 直接将markdown转换为word pandoc -f markdown -t docx ./test.md -o test.docx 关于markdown转为 ...

  10. uva208

    一道简单的路径打印,首先需要一次dfs判断能否从1到达目标点,否则可能会超时.还有一点就是那个格式需要注意下,每条路径前没有空格(看起来好像有3个空格)-. AC代码: #include<cst ...