Prim最小生成树板子
普里姆算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
邻接矩阵存图 时间复杂度O(n^2)
1.算法过程描述
给出一个无向图G=<V,E>
- 图的所有顶点集合为V;分成两个集合 初始令集合U= {s} , V'=V−U;
- 在两个集合U,V'能够组成的边中,选择一条代价最小的边(u0,v0)( u0∈U,v0∈V'),加入到最小生成树中,并把v0并入到集合U中。
- 重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。
由于不断向集合U中加点,所以最小代价边必须同步更新;需要建立一个辅助数组lowcost,用来维护集合V'中每个顶点与集合U中最小代价边信息
2.算法实现
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn= 1e4+10; 4 const double eps= 1e-6; 5 const int inf = 0x3f3f3f3f; 6 const int mod =3; 7 typedef long long ll; 8 typedef long double ld; 9 int g[maxn][maxn]; 10 int mst[maxn]; 11 int lowcost[maxn]; 12 int n,m; 13 int prim(int x) //从x点开始扩展 14 { 15 int sum=0; //边权和 16 for(int i=1;i<=n;i++) 17 { 18 lowcost[i]=g[x][i]; //lowcost[i]表示以i为终点的边中最小的权值,等于-1 表示已在集合U中
//mst[i]=x; //记录路径的话 开个mst数组 mst[i]=x;表示当前集合U中到点的距离最小的点为x 即边(x,i)为候选边 19 } 20 lowcost[x]=-1; 21 for(int i=1;i<=n-1;i++) 22 { 23 int mind=inf,minid=0; 24 for(int j=1;j<=n;j++) 25 { 26 if(lowcost[j]<mind&&lowcost[j]!=-1) 27 { 28 mind=lowcost[j]; //选出最小值(要加入最小生成树的边的边权) 29 minid=j; //记录要加入的点 30 } 31 } 32 sum+=mind; 33 lowcost[minid]=-1; 34 for(int i=1;i<=n;i++) 35 { 36 if(lowcost[i]>g[minid][i]) //更新候选值 37 { 38 lowcost[i]=g[minid][i]; 39 } 40 } 41 } 42 return sum; //返回最小生成树边权值和 43 } 44 int main() 45 { 46 while(scanf("%d %d",&n,&m)!=EOF) //n个点,m条边 47 { 48 for(int i=1; i<=n; i++) //赋初值 49 { 50 for(int j=1; j<=n; j++) 51 g[i][j]=inf; 52 } 53 int u,v,w; 54 for(int i=0;i<m;i++) 55 { 56 scanf("%d %d %d",&u,&v,&w); 57 g[u][v]=g[v][u]=w; 58 } 59 int sum=prim(1); 60 printf("%d\n",sum); 61 } 62 }
相关 裸题 http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1212
3.简单证明prim算法
反证法:假设prim生成的不是最小生成树
1).设prim生成的树为G0
2).假设存在Gmin使得cost(Gmin)<cost(G0) 则在Gmin中存在<u,v>不属于G0
3).将<u,v>加入G0中可得一个环,且<u,v>不是该环的最长边(这是因为<u,v>∈Gmin)
4).这与prim每次生成最短边矛盾
5).故假设不成立,命题得证.