最小生成树两个重要的算法: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 }

 

 

 

posted @ 2012-07-31 20:55  max_xbw  阅读(304)  评论(0编辑  收藏  举报