MST最小生成树及Prim普鲁姆算法

当前位置 : 首页 > 网页制作 > CSS > MST最小生成树及Prim普鲁姆算法

MST最小生成树及Prim普鲁姆算法

来源: 作者: 时间:2016-01-29 09:12
MST在前面学习了Kruskal算法,还有一种算法叫做Prim的。这两者的区别是Prim算法适合稠密图,比如说鸟巢这种几乎所有点都有相连的图。其时间复杂度为O(n^2),其时间复杂度与边的数目无
MST在前面学习了Kruskal算法,还有一种算法叫做Prim的。这两者的区别是Prim算法适合稠密图,比如说鸟巢这种几乎所有点都有相连的图。其时间复杂度为O(n^2),其时间复杂度与边的数目无关;而kruskal算法的时间复杂度为O(eloge),跟边的数目有关,适合稀疏图。
 
 
prim算法
  
基本思想:假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U={u0}(u0∈V),TE={ 空集 }开始。重复执行下列操作:
   
1.在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止;接下里以 v0为边的起点,继续寻找权值最小的边并入集合TE中,依次往复;
   
2.最后,TE中必有n-1条边,T=(V,TE)为G的最小生成树。
   
Prim算法的核心:始终保持TE中的边集构成一棵生成树,也就是它与Kruskal算法的主要区别是,Prim是一直保持一种串联的状态而不遵从整体的贪心算法。其实初始点uo的选择可以随意,一般做题题目条件会给出或者取最小的权值边。
其实现的代码如下:
 
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  

 

 
 
#define infinity 1000000  
#define max_vertexes 6   
 

 

 
typedef int Graph[max_vertexes][max_vertexes];  
 

 

void prim(Graph G,int ount,int father[])  
{      
int i,j,k;   
int lowcost[max_vertexes];  
int closeset[max_vertexes],used[max_vertexes];  
int min;    
for (i=0;i<vcount;i++)       
  {  
/* 最短距离初始化为其他节点到1号节点的距离 */     
    lowcost[i]=G[0][i];  
    /* 标记所有节点的依附点皆为默认的1号节点 */  
     closeset[i]=0;        
  used[i]=0;      
    father[i]=-1;        
}      
used[0]=1; /*第一个节点是在s集合里的*/  
/* vcount个节点至少需要vcount-1条边构成最小生成树 */    
  for (i=1;i<=vcount-1;i++)        
   {         
 j=0;  
     min = infinity;  
       /* 找满足条件的最小权值边的节点k */        
     for (k=1;k<vcount;k++)  
         /* 边权值较小且不在生成树中 */       
 if ((!used[k])&&(lowcost[k]<min))   
    {  
              min =  lowcost[k];  
              j=k;  
            }         
    father[j]=closeset[j];     
printf("%d %d\n",j+1,closeset[j]+1);//打印边     
used[j]=1;;//把第j个顶点并入了U中       
for (k=1;k<vcount;k++)  
         /* 发现更小的权值 */         
   if (!used[k]&&(G[j][k]<lowcost[k]))         
{   
                  lowcost[k]=G[j][k];/*更新最小权值*/         
      closeset[k]=j;;/*记录新的依附点*/  
    }        
   }  
}  
                   
int main()  
{  
FILE *fr;  
int i,j,weight;  
Graph G;  
int fatheer[max_vertexes];  
for(i=0; i<max_vertexes; i++)  
for(j=0; j<max_vertexes; j++)  
G[i][j] = infinity;  
fr = fopen("prim.txt","r");  
if(!fr)  
{  
printf("fopen failed\n");  
exit(1);   
}  
while(fscanf(fr,"%d%d%d", &i, &j, &weight) != EOF)  
{  
G[i-1][j-1] = weight;  
G[j-1][i-1] = weight;  
}  
prim(G,max_vertexes,fatheer);  
return 0;  
}  

 邻接矩阵的形式进行存储的实现:
<pre name="code" class="">#include <stdio.h>  
#define n 6  
#define MaxNum 10000  /*定义一个最大整数*/  
  
/*定义邻接矩阵类型*/  
typedef int adjmatrix[n+1][n+1];   /*0号单元没用*/  
  
typedef struct{  
    int fromvex,tovex;  
    int weight;  
}Edge;  
typedef Edge *EdgeNode;  
  
int arcnum;     /*边的个数*/  
  
/*建立图的邻接矩阵*/  
void CreatMatrix(adjmatrix GA){  
    int i,j,k,e;  
    printf("图中有%d个顶点\n",n);  
    for(i=1;i<=n;i++){  
        for(j=1;j<=n;j++){  
            if(i==j){  
                GA[i][j]=0;         /*对角线的值置为0*/  
            }  
            else{  
                GA[i][j]=MaxNum;    /*其它位置的值置初始化为一个最大整数*/  
            }  
        }  
    }  
    printf("请输入边的个数:");  
    scanf("%d",&arcnum);  
    printf("请输入边的信息,按照起点,终点,权值的形式输入:\n");  
    for(k=1;k<=arcnum;k++){  
        scanf("%d,%d,%d",&i,&j,&e);  /*读入边的信息*/  
        GA[i][j]=e;  
        GA[j][i]=e;  
    }  
}  
  
/*初始化图的边集数组*/  
void InitEdge(EdgeNode GE,int m){  
    int i;  
    for(i=1;i<=m;i++){  
        GE[i].weight=0;  
    }  
}  
  
/*根据图的邻接矩阵生成图的边集数组*/  
void GetEdgeSet(adjmatrix GA,EdgeNode GE){  
    int i,j,k=1;  
    for(i=1;i<=n;i++){  
        for(j=i+1;j<=n;j++){  
            if(GA[i][j]!=0&&GA[i][j]!=MaxNum){  
                GE[k].fromvex=i;  
                GE[k].tovex=j;  
                GE[k].weight=GA[i][j];  
                k++;  
            }  
        }  
    }  
}  
  
/*按升序排列图的边集数组*/  
void SortEdge(EdgeNode GE,int m){  
    int i,j,k;  
    Edge temp;  
    for(i=1;i<m;i++){  
        k=i;  
        for(j=i+1;j<=m;j++){  
            if(GE[k].weight>GE[j].weight){  
                k=j;  
            }  
        }  
        if(k!=i){  
            temp=GE[i];GE[i]=GE[k];GE[k]=temp;  
        }  
    }  
}  
  
/*利用普里姆算法从初始点v出发求邻接矩阵表示的图的最小生成树*/  
void Prim(adjmatrix GA,EdgeNode T){  
    int i,j,k,min,u,m,w;  
    Edge temp;  
    /*给T赋初值,对应为v1依次到其余各顶点的边*/  
    k=1;  
    for(i=1;i<=n;i++){  
        if(i!=1){  
            T[k].fromvex=1;  
            T[k].tovex=i;  
            T[k].weight=GA[1][i];  
            k++;  
        }  
    }  
    /*进行n-1次循环,每次求出最小生成树中的第k条边*/  
    for(k=1;k<n;k++){  
        min=MaxNum;  
        m=k;  
        for(j=k;j<n;j++){  
            if(T[j].weight<min){  
                min=T[j].weight;m=j;  
            }  
        }  
        /*把最短边对调到k-1下标位置*/  
        temp=T[k];  
        T[k]=T[m];  
        T[m]=temp;  
        /*把新加入最小生成树T中的顶点序号赋给j*/  
        j=T[k].tovex;  
        /*修改有关边,使T中到T外的每一个顶点保持一条到目前为止最短的边*/  
        for(i=k+1;i<n;i++){  
            u=T[i].tovex;  
            w=GA[j][u];  
            if(w<T[i].weight){  
                T[i].weight=w;T[i].fromvex=j;  
            }  
        }  
    }  
}  
  
/*输出边集数组的每条边*/  
void OutEdge(EdgeNode GE,int e){  
    int i;  
    printf("按照起点,终点,权值的形式输出的最小生成树为:\n");  
    for(i=1;i<=e;i++){  
        printf("%d,%d,%d\n",GE[i].fromvex,GE[i].tovex,GE[i].weight);  
    }  
}  
  
void main(){  
    adjmatrix GA;  
    Edge GE[n*(n-1)/2],T[n];  
    CreatMatrix(GA);  
    InitEdge(GE,arcnum);  
    GetEdgeSet(GA,GE);  
    SortEdge(GE,arcnum);  
    Prim(GA,T);  
    printf("\n");  
    OutEdge(T,n-1);  
}</pre><br>  
<br>  
<p></p>  
<pre></pre>  
<p></p>  

 

 
Tag:
网友评论

<