Prim最小生成树板子

普里姆算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

邻接矩阵存图  时间复杂度O(n^2) 

1.算法过程描述

   给出一个无向图G=

  1. 图的所有顶点集合为V;分成两个集合 初始令集合U{s, V'=V−U;
  2. 在两个集合U,V'能够组成的边中,选择一条代价最小的边(u0,v0)( u0∈U,v0∈V'),加入到最小生成树中,并把v0并入到集合U中。
  3. 重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。

由于不断向集合U中加点,所以最小代价边必须同步更新;需要建立一个辅助数组lowcost,用来维护集合V'中每个顶点与集合U中最小代价边信息

 

2.算法实现    

 1 #include
 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]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) 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)0)   则在Gmin中存在不属于G0

3).将加入G0中可得一个环,且不是该环的最长边(这是因为∈Gmin)

4).这与prim每次生成最短边矛盾

5).故假设不成立,命题得证.

转载于:https://www.cnblogs.com/stranger-/p/7989480.html

你可能感兴趣的:(Prim最小生成树板子)