zoukankan      html  css  js  c++  java
  • 最小生成树两个重要的算法:Prim 和 Kruskal

    最小生成树两个重要的算法:Prim 和 Kruskal。

    Prim:时间复杂度O(n^2),适用于边稠密的网络。

    Kruskal:时间复杂度为O(e*log(e)),适用于边稀疏的网络。

    【Prim主要算法思想和函数】

    注:扩展了部分功能,根据需要可以选择得到算法结束时哪些边被选择。

     1 #include <iostream>
     2 using namespace std;
     3 
     4 const int N=101;
     5 
     6 struct Edge
     7 {
     8     int from;
     9     int to;
    10 };
    11 
    12 int matrix[N][N];

    /*
    最小生成树之Prim算法:
    算法思想:选定一点到当前树集合,迭代合并距离当前树最近的点,同时更新剩余的点到当前树的"距离"
    n:点的个数;
    cost:边的权值,无边用0x3f3f3f3f表示无穷大;(建议初始化cost的时候:memset(cost,0x3f,sizeof(cost));)
    edge_arr存放结果选定的边(此功能可选,默认参数为不选)
    */

     1 template <class T>
     2 T MST_Prim(const int & n,T cost[][N],Edge * edge_arr=NULL)
     3 {
     4     int i,j;
     5     T ans=0;
     6     T dis[N]; //用于记录当前每个点到当前的树的距离
     7     int pre[N];
     8     bool vst[N]={false}; //用于标记点是否在当前树上
     9     for(vst[0]=true,i=0;i<n;i++)
    10         dis[i]=cost[0][i],pre[i]=0;
    11     for(i=1;i<n;i++)
    12     {
    13         int idx=-1;
    14         T Min=0x3f3f3f3f;
    15         for(j=0;j<n;j++)
    16         {
    17             if(! vst[j] && dis[j]<Min)
    18             {
    19                 idx=j;
    20                 Min=dis[j];
    21             }
    22         }
    23         if(idx==-1)
    24             return -1;
    25         vst[idx]=true;
    26         ans+=dis[idx];
    27         if(edge_arr)
    28         {
    29             edge_arr[i-1].from=pre[idx];
    30             edge_arr[i-1].to=idx;
    31         }
    32         for(j=0;j<n;j++)
    33         {
    34             if(! vst[j] && cost[idx][j]<dis[j])
    35                 dis[j]=cost[idx][j],pre[j]=idx;
    36         }
    37     }
    38     return ans;
    39 }
    40 
    41 int main()
    42 {
    43     int n;
    44     while(scanf("%d",&n)!=EOF)
    45     {
    46         int i,j;
    47         for(i=0;i<n;i++)
    48         {
    49             for(j=0;j<n;j++)
    50                 scanf("%d",&matrix[i][j]);
    51         }
    52         printf("%d\n",MST_Prim(n,matrix));
    53     }
    54     return 0;
    55 }

    【Kruskal算法思想和函数】

    /*
    并查集的一个特性:
    用一个数组p[]表示每一个元素的父级元素
    最父级的元素的父级元素是一个负数,这个负数的绝对值是这个集合下的元素的个数
    */

     1 template <class T>
     2 bool operator <(const Edge<T> & a,const Edge<T> & b)
     3 {
     4     return a.cost<b.cost;
     5 }
     6 
     7 /*
     8 找到x所在集合的最父级代表元素
     9 如果这个集合只有x自己,那么最父级代表元素当然就是它自己
    10 */
    11 int FindSet(int * p,int x)
    12 {
    13     int tmp,px=x;
    14     while(p[px]>=0) //找到x所在集合的代表元素
    15         px=p[px];
    16     /*
    17     路径压缩,可选,如果需要频繁查询,压缩之后可以提高速度
    18     即把从x到代表元素路径上的所有的元素的父节点都表示为代表元素
    19     */
    20     while(p[x]>=0)
    21     {
    22         tmp=p[x];
    23         p[x]=px;
    24         x=tmp;
    25     }
    26     return px; //x元素所在集合的代表元素
    27 }
    28 
    29 /*
    30 合并x和y所在的集合.
    31 */
    32 void UnionSet(int * p,int x,int y)
    33 {
    34     int tmp;
    35     x=FindSet(p,x);
    36     y=FindSet(p,y);
    37     if(x==y)
    38         return ;
    39     tmp=p[x]+p[y];
    40     if(p[x]>p[y]) //将小树合并到大树下
    41     {
    42         p[y]=tmp;
    43         p[x]=y;
    44     }
    45     else
    46     {
    47         p[x]=tmp;
    48         p[y]=x;
    49     }
    50     return ;
    51 }

    /*
    最小生成树算法之Kruskal算法:
    算法思想:每次找最小的边,如果在已有的森林中加入该边后会形成回路,则舍弃,否则加入然后合并森林
    n:点的个数;
    edge_cnt:边的个数
    edge[]:保存边的数组
    edge_arr:保存选择边的数组,可选功能
    */

     1 #include <algorithm>
     2 #include <iostream>
     3 using namespace std;
     4 
     5 const int N=1001; //定义能处理的最大点的个数
     6 
     7 template <class T>
     8 struct Edge
     9 {
    10     int from;
    11     int to;
    12     T cost;
    13 };
    14 
    15 template <class T>
    16 T MST_Kruskal(const int & n,const int & edge_cnt,Edge<T> edge[],Edge<T> * edge_arr=NULL)
    17 {
    18     T ans=0;
    19     int i,x,y,p[N],cnt=0;
    20     memset(p,-1,sizeof(p));
    21     sort(edge,edge+edge_cnt);
    22     for(i=0;i<edge_cnt;i++)
    23     {
    24         x=FindSet(p,edge[i].from);
    25         y=FindSet(p,edge[i].to);
    26         if(x!=y)
    27         {
    28             UnionSet(p,x,y);
    29             ans+=edge[i].cost;
    30             if(edge_arr)
    31                 edge_arr[cnt]=edge[i];
    32             cnt++;
    33             if(cnt==n-1)
    34                 return ans;
    35         }
    36     }
    37     return -1;
    38 }
  • 相关阅读:
    漂亮灵活设置的jquery通知提示插件toastr
    C# 对List<T>取交集、连集及差集
    查看sqlserver被锁的表以及如何解锁.
    javascript的setTimeout()用法总结,js的setTimeout()方法
    日志插件 log4net 的使用
    Log4NET简介
    解决WCF大数据量传输 ,System.Net.Sockets.SocketException: 远程主机强迫关闭了一个现有的连接
    也说Autofac在MVC的简单实践:破解在Controller构造函数中的实例化
    Autofac 依赖注入 ASP.NET MVC5 插件机制中插件的简单实现
    Asp.net mvc中整合autofac
  • 原文地址:https://www.cnblogs.com/XBWer/p/2617370.html
Copyright © 2011-2022 走看看