zoukankan      html  css  js  c++  java
  • 最小生成树-Kruskal算法

    Prim算法贪心选择不同,Kruskal算法采取每次选择权值最小的边的方法,这样,在不构成环且最后能够连接完所有边它们的权重和一定是最小的。

    和之前Prim算法的图一样,便于区别二者。

    Kruskal既然是选择最小的边,那么就先找一个最小的出来,是1-6(10)

    然后继续找出剩下的边中最小一条边,是3-4(12)

    继续找一条最小的出来,2-7(14)

    在来,为了区别已经选择的点,我把点的颜色也做个标记,有颜色的表示为已经加入生成树的点

    喔,忘了把最小的边2-3(16)选了

    现在图变成了这样,(依旧难看).......

    还没找完,继续找最小的边..是7-4(18)

    你会发现我把这条边用蓝色标记了,是不是我为了好玩??当然不是了,这条边是有问题的。

    这条边虽然是上一次选择完后剩下的边中最短的,但是,它的左右两个点已经是最小生成树的结点了,而把这条边加入后,构成了右边的一个大大的环。这样显然不是最小生成树了.

    再复习下,生成树:一个连通图的生成树,是一个极小连通子图,其中包含图的所有结点,和构成一棵数的(n-1)条边。如果在一棵生成树的两个结点上添加任意一边,必定构成一个环。

    最小生成树:图的所有生成树中所有边的权值和最小的那个生成树

    所以,有环的连生成树都不是了,怎么会是最小生成树。。

    所以,这条边7-4(18)丢掉丢掉,重新选择。选择5-4(22)

    好像图中所有的点都有颜色了,但是还没完全好,因为它们还不是一条绳上的蚂蚱,

    继续选,最短的是6-5(25)

    继续选 ,唉,不对,选了24发现又有环了,选28也构成环了。。。。在仔细一看,最小生成树已经生成了

    这个就是Kruskal算法的流程。那么接下来说说代码。

     1 struct node
     2 {
     3     int u;
     4     int v;
     5     int w;//边的权重
     6 }Edge;
     7 void Kruskal(Graph g)//无向图g采用邻接矩阵
     8 {
     9     Edge E[MAXN];//存放图中所有的边
    10     int vest[MAXN];//辅助数组,存放连通的点的编号
    11     k = 0;
    12     for(int i = 0;i < g.n;i++)
    13     {
    14         for(int j = 0; j <= i ;j++)
    15         {
    16             if(g.egdes[i][j] != 0 &&g.egdes[i][j]!= INF)
    17             {//说明i到j边
    18                 E.[k].u = i;
    19                 E.[k].v = j;
    20                 E.[k].w = g.edges[i][j];
    21                 k++;
    22             }
    23         }
    24     }//以上将所有的边都加入到E数组中,肯定是不重复的
    25     Sort(E);//对边集数组进行排序。
    26     Init(vest);//将辅助数组初始化,即每个结点一开始都没有加入到最小生成树中,所以它们各自为一个阵营
    27     j = 0;
    28     Count = 0 ;
    29     while(Count < g.n)//已经加入生成树的结点数小于图的结点数,表明生成树没生成完,
    30     {
    31         u1 = E[j].u;
    32         v1 = E[j].v;//选出最短的边
    33         s1 = vest[u1];
    34         s2 = vest[v1];//得到两个所在集合的编号,
    35         if(s1 != s2)//如果它们编号不等,,说明它们还每加入到同一个生成树中,
    36         {
    37             //这里可以打印它们的编号 。。。
    38             k++;
    39             for(int i = 0; i< g.n;i++)
    40             {
    41                 if(vest[i]==s2)
    42                 {
    43                     vest[i] = s1;//把属于s2的那个点加入到s1所在点集合中
    44                 }//即合并到一起去,表明它们在一个生成树中了,这样就和
    45                 //其他没有加入到的点区分开了
    46             }
    47         }
    48         j++;//继续找下一条边
    49     }
    50 }
    View Code

    这个代码没有写全,因为这样用的次数少的可怜了。都用它的升级版了

    首先,针对排序的问题,排序随你选,接下来就是判断是否构成环的问题了。这里用并查集轻易的实现

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<vector>
     6 #include<stack>
     7 #include<map>
     8 #include<set>
     9 #include<list>
    10 #include<queue>
    11 #include<string>
    12 #include<algorithm>
    13 #include<iomanip>
    14 using namespace std;
    15 const int maxn = 100;
    16 int par[maxn];
    17 int rank[maxn];
    18 int n;
    19 int m;
    20 
    21 struct node
    22 {
    23     int Start;
    24     int End;
    25     int weight;
    26 }edges[maxn];
    27 
    28 int cmp(node a,node b)//按权值从小到大排序
    29 {
    30     return a.weight < b.weight;
    31 }
    32 
    33 void Init(int n)//par初始化为自己
    34 {
    35     for(int i = 1;i <= n;i++)
    36     {
    37         par[i] = i;
    38     }
    39 }
    40 int  Find(int x)//找出父亲结点
    41 {
    42     if(x != par[x])return x =Find(par[x]);
    43     return x;
    44 }
    45 
    46 int  Kruskal()
    47 {
    48     int sum = 0;
    49     for(int i = 1;i <= m ;i++)
    50     {
    51         int a = Find(edges[i].Start);
    52         int b = Find(edges[i].End);
    53         if(a != b)//父亲结点不同
    54         {
    55             sum += edges[i].weight;//一般求最小生成树的长度,这里就没去掉
    56             par[a] = b;//合并集合
    57         }
    58     }
    59     return sum;
    60 }
    61 
    62 int main()
    63 {
    64     
    65     cin>>n>>m;
    66     Init(n);
    67     for(int i = 1;i <= m;i++)
    68     {
    69         cin>>edges[i].Start>>edges[i].End>>edges[i].weight;
    70     }
    71     sort(edges+1,edges+1+n,cmp); 
    72     cout<<Kruskal();
    73     return 0;
    74 }
    View Code

    传送门:NetWork  不会的点这里

     

  • 相关阅读:
    Atitit attilax要工作研究的要素 纪要 方案 趋势 方向 概念 理论
    Atitit 常见每日流程日程日常工作.docx v7 r8f
    Atitit it 互联网 软件牛人的博客列表
    Atitit 信息链(Information Chain)的概念理解 attilax总结
    Atitit 知识点的体系化 框架与方法 如何了解 看待xxx
    Atitit 聚合搜索多个微博 attilax总结
    Atitit 企业知识管理PKM与PIM
    Atitit 项目沟通管理 Atitit 沟通之道 attilax著.docx
    Atitit 项目管理软件 在线服务 attilax总结 1. 项目管理协作的历史 1 1.1. Worktile 406k 1 1.2. Teambition  584k in baidu
    Atitit.每周末总结 于每周一计划日程表 流程表 v8 import 上周遗漏日志补充 检查话费 检查流量情况 Crm问候 Crm表total and 问候
  • 原文地址:https://www.cnblogs.com/ygsworld/p/11256505.html
Copyright © 2011-2022 走看看