概要:
- Prim算法
- Kruskal算法
1、Prim算法
算法流程:
(1)对图G(V,E)设置集合S来存放已被并入的顶点,然后执行n次(2)(3)
(2)每次从未并入顶点集合中选择与集合S最近的一个顶点,访问u并将其加入集合S,同时把这条离集合S最近的边加入最小生成树中。
(3)优化松弛
Prim算法与Dijkstra算法使用的思想几乎完全相同,只有在数组d[]的含义上有区别。(关于Dijkstra算法具体可以看前面写的《图的算法专题——最短路径》)
Dijkstra中d[]含义为起点s到达顶点Vi的最短距离,而Prim算法d[]含义为顶点Vi与集合S的最短距离,两者区别仅在于最短距离是到 起点 还是 集合 。
邻接矩阵版:
1 const int maxn=1000; 2 const int INF=1000000000; 3 int n,G[maxn][maxn]; 4 int d[maxm]; //顶点到集合S的距离 5 bool vis[maxn]={ false}; 6 7 int prim(){ //默认0号为初始点,函数返回最小生成树的边权之和 8 fill(d,d+maxn,INF); 9 d[0]=0; 10 int ans=0; //边权之和 11 for(int i=0;i){ 12 int u=-1,MIN=INF; 13 for(int j=0;j){ 14 if(vis[j]==false&&d[j]<MIN){ 15 u=j; 16 MIN=d[j]; 17 } 18 } 19 if(u==-1) return -1; 20 vis[u]=true; 21 ans+=d[u]; //将与集合S距离最小的边加入最小生成树 22 for(int v=0;v ){ 23 if(vis[v]==false && G[u][v]!=INF && G[u][v]<d[v] ){ 24 d[v]=G[u][v]; //以u为中介点可以使v离集合S更近(u已被并入集合) 25 } 26 } 27 } 28 return ans; 29 }
邻接表版:
1 struct Node{ 2 int v,dis; //v为目标顶点,dis为边权 3 }; 4 vectorAdj[maxn]; 5 int n,d[maxn]; 6 bool vis[maxn]={ false}; 7 int prim(){ 8 fill(d,d+maxn,INF); 9 d[0]=0; 10 int ans=0; 11 for(int i=0;i 12 int u=-1,MIN=INF; 13 for(int j=0;j){ ){ 14 if(vis[j]==false && d[j]<MIN){ 15 u=j; 16 MIN=d[j]; 17 } 18 } 19 if(u==-1) return -1; 20 vis[u]=true; 21 ans+=d[u]; 22 for(int j=0;j ){ 23 int v=Adj[u][j].v; 24 if(vis[v]==false && Adj[u][j].dis< d[v]){ 25 d[v]=Adj[u][j].dis; 26 } 27 } 28 } 29 return ans; 30 }
2、Kruskal算法
算法流程:
(1)对所有边权从小到大排序。
(2)按边权从小到大测试所有边,如果当前测试边所连接的两个顶点不在同一个连通块中,则并入,否则舍弃。 (运用并查集)
(3)循环执行(2)直到最小生成树的边数等于总顶点数减1或是测试完所有边时结束。若结束时边数不为顶点数减1,则图不连通。
1 const int MAXV=110; 2 const int MAXE=10010; 3 int father[MAXV]; 4 int findFather(int x){ 5 int a=x; 6 while(x!=father[x]){ 7 x=father[x]; 8 } 9 while(a!=father[a]){ 10 int z=a; 11 a=father[a]; 12 father[z]=x; 13 } 14 return x; 15 } 16 struct edge{ 17 int u,v; //边的两个端点编号 18 int cost; //边权 19 }E[MAXE]; 20 bool cmp(edge a,edge b){ 21 return a.cost<b.cost; 22 } 23 int kruskal(int n,int m){ //n为顶点个数,m为图的边数 24 int ans=0,Num_Edge=0; 25 for(int i=1;i<=n;i++) father[i]=i; //假设顶点范围为1到n 26 sort(E,E+m,cmp); 27 for(int i=0;i// 枚举边 28 int faU=findFather(E[i].u); 29 int faV=findFather(E[i].v); 30 if(faU!=faV){ 31 father[faU]=faV; 32 ans+=E[i].cost; 33 Num_Edge++; 34 if(Num_Edge==n-1) break; 35 } 36 } 37 if(Num_Edge != n-1) return -1; 38 else return ans; 39 }