最小生成树两个重要的算法:Prim 和 Kruskal
2012-07-31 20:55
375 查看
最小生成树两个重要的算法:Prim 和 Kruskal。
Prim:时间复杂度O(n^2),适用于边稠密的网络。
Kruskal:时间复杂度为O(e*log(e)),适用于边稀疏的网络。
【Prim主要算法思想和函数】
注:扩展了部分功能,根据需要可以选择得到算法结束时哪些边被选择。
/*
最小生成树之Prim算法:
算法思想:选定一点到当前树集合,迭代合并距离当前树最近的点,同时更新剩余的点到当前树的"距离"
n:点的个数;
cost:边的权值,无边用0x3f3f3f3f表示无穷大;(建议初始化cost的时候:memset(cost,0x3f,sizeof(cost));)
edge_arr存放结果选定的边(此功能可选,默认参数为不选)
*/
【Kruskal算法思想和函数】
/*
并查集的一个特性:
用一个数组p[]表示每一个元素的父级元素
最父级的元素的父级元素是一个负数,这个负数的绝对值是这个集合下的元素的个数
*/
/*
最小生成树算法之Kruskal算法:
算法思想:每次找最小的边,如果在已有的森林中加入该边后会形成回路,则舍弃,否则加入然后合并森林
n:点的个数;
edge_cnt:边的个数
edge[]:保存边的数组
edge_arr:保存选择边的数组,可选功能
*/
Prim:时间复杂度O(n^2),适用于边稠密的网络。
Kruskal:时间复杂度为O(e*log(e)),适用于边稀疏的网络。
【Prim主要算法思想和函数】
注:扩展了部分功能,根据需要可以选择得到算法结束时哪些边被选择。
#include <iostream> using namespace std; const int N=101; struct Edge { int from; int to; }; int matrix ;
/*
最小生成树之Prim算法:
算法思想:选定一点到当前树集合,迭代合并距离当前树最近的点,同时更新剩余的点到当前树的"距离"
n:点的个数;
cost:边的权值,无边用0x3f3f3f3f表示无穷大;(建议初始化cost的时候:memset(cost,0x3f,sizeof(cost));)
edge_arr存放结果选定的边(此功能可选,默认参数为不选)
*/
template <class T> T MST_Prim(const int & n,T cost[] ,Edge * edge_arr=NULL) { int i,j; T ans=0; T dis ; //用于记录当前每个点到当前的树的距离 int pre ; bool vst ={false}; //用于标记点是否在当前树上 for(vst[0]=true,i=0;i<n;i++) dis[i]=cost[0][i],pre[i]=0; for(i=1;i<n;i++) { int idx=-1; T Min=0x3f3f3f3f; for(j=0;j<n;j++) { if(! vst[j] && dis[j]<Min) { idx=j; Min=dis[j]; } } if(idx==-1) return -1; vst[idx]=true; ans+=dis[idx]; if(edge_arr) { edge_arr[i-1].from=pre[idx]; edge_arr[i-1].to=idx; } for(j=0;j<n;j++) { if(! vst[j] && cost[idx][j]<dis[j]) dis[j]=cost[idx][j],pre[j]=idx; } } return ans; } int main() { int n; while(scanf("%d",&n)!=EOF) { int i,j; for(i=0;i<n;i++) { for(j=0;j<n;j++) scanf("%d",&matrix[i][j]); } printf("%d\n",MST_Prim(n,matrix)); } return 0; }
【Kruskal算法思想和函数】
/*
并查集的一个特性:
用一个数组p[]表示每一个元素的父级元素
最父级的元素的父级元素是一个负数,这个负数的绝对值是这个集合下的元素的个数
*/
template <class T> bool operator <(const Edge<T> & a,const Edge<T> & b) { return a.cost<b.cost; } /* 找到x所在集合的最父级代表元素 如果这个集合只有x自己,那么最父级代表元素当然就是它自己 */ int FindSet(int * p,int x) { int tmp,px=x; while(p[px]>=0) //找到x所在集合的代表元素 px=p[px]; /* 路径压缩,可选,如果需要频繁查询,压缩之后可以提高速度 即把从x到代表元素路径上的所有的元素的父节点都表示为代表元素 */ while(p[x]>=0) { tmp=p[x]; p[x]=px; x=tmp; } return px; //x元素所在集合的代表元素 } /* 合并x和y所在的集合. */ void UnionSet(int * p,int x,int y) { int tmp; x=FindSet(p,x); y=FindSet(p,y); if(x==y) return ; tmp=p[x]+p[y]; if(p[x]>p[y]) //将小树合并到大树下 { p[y]=tmp; p[x]=y; } else { p[x]=tmp; p[y]=x; } return ; }
/*
最小生成树算法之Kruskal算法:
算法思想:每次找最小的边,如果在已有的森林中加入该边后会形成回路,则舍弃,否则加入然后合并森林
n:点的个数;
edge_cnt:边的个数
edge[]:保存边的数组
edge_arr:保存选择边的数组,可选功能
*/
#include <algorithm> #include <iostream> using namespace std; const int N=1001; //定义能处理的最大点的个数 template <class T> struct Edge { int from; int to; T cost; }; template <class T> T MST_Kruskal(const int & n,const int & edge_cnt,Edge<T> edge[],Edge<T> * edge_arr=NULL) { T ans=0; int i,x,y,p ,cnt=0; memset(p,-1,sizeof(p)); sort(edge,edge+edge_cnt); for(i=0;i<edge_cnt;i++) { x=FindSet(p,edge[i].from); y=FindSet(p,edge[i].to); if(x!=y) { UnionSet(p,x,y); ans+=edge[i].cost; if(edge_arr) edge_arr[cnt]=edge[i]; cnt++; if(cnt==n-1) return ans; } } return -1; }
相关文章推荐
- 最小生成树两种算法。kruskal和prim
- C++代码,数据结构-最小生成树的两个算法,Prime&Kruskal
- 最小生成树算法Prim、Kruskal
- 【算法复习】图的最小生成树(Prim&Kruskal)
- 最小生成树算法:prim和kruskal
- 图的广度遍历、深度遍历及最小生成树书算法(Prim、Kruskal)
- 最小生成树之克鲁斯卡尔(Kruskal)算法、普里姆(prim)算法
- 最小生成树 prim 算法 与kruskal 算法
- 最小生成树算法介绍(转载)Prim+Kruskal
- 最小生成树算法(Prim+Kruskal)
- 最小生成树的两种算法图解(Kruskal与prim)
- 最小生成树算法(Prim和Kruskal)
- 算法记录---最小生成树【kruskal&&prim】
- 算法整理:最小生成树(mst)-Prim+Kruskal
- 最小生成树 ,prim 和Kruskal 算法
- hdu 1233 还是畅通工程(最小生成树的Prim和Kruskal两种算法的c++实现)(prim算法详解)
- 关于图的常用算法——Dijkstra单源最短路径、Floyd多源最短路径、Prim和Kruskal最小生成树算法
- 数据结构之最小生成树的Prim和Kruskal`s 算法
- 图论中最小生成树算法-Prim(普里姆)算法、kruskal(克鲁斯卡尔避圈法)算法、破圈算法
- 最小生成树(MST)----普里姆(Prim)算法与克鲁斯卡尔(Kruskal)算法