最小生成樹--Prim算法


最小生成樹的概念:

       最小生成樹是基於“帶權圖” 的,即圖中每條邊上都有特定的權值,這樣的圖又稱為網。最小生成樹指的是所有生成樹中,權值之和最小的樹。

Prim算法:

       假設G=(V,E)為一網圖,其中V為頂點的集合,E為邊的集合。從某一頂點u1出發,選擇與它關聯的具有最小權值的邊(u1, v),將其頂點v加入到生成樹頂點

集合U中。U用於存放G的最小生成樹中的頂點,T存放G的最小生成樹中的邊。

令集合U的初值為U={u1} (假設構造最小生成樹時,從頂點u1出發),集合T的初值為T={ }。

      以后每一步從U中選擇一個頂點u(u屬於U),而另一個頂點v屬於V-U的邊中,選取具有最小權值的邊(u,v),將頂點v加入集合U中,將邊(u,v)加入集合T

中,如此不斷重復,直到U=V時,最小生成樹構造完畢,這時集合T中包含了最小生成樹的所有邊。

Prim算法的描述:

(1)U={u1} , T={ }

  (2)  while(U<>V)

        (u,v)=min{Wuv ; u屬於U, v屬於V-U};

        T=T+{ (u, v) };

        U=U + { v }.

 (3) 結束

 

 

在構造過程中,設置了兩個輔助數組:lowcost[]存放生成樹頂點集合U內頂點到生成樹外V-U各頂點的各邊上的當前最小權值;

nearvex[]記錄生成樹頂點集合外各頂點距離集合內哪個頂點最近(即權值最小).

若選擇從頂點0出發,即u=0, 則兩個輔助數組的初始狀態為:

 

反復做以下工作:

(1) 在lowcost[ ]中選擇nearvec[ ]<>-1 && lowcost[i]最小的邊,用v標記它。則選中的權值最小的邊為(nearvex[v] , v),相應的權值為lowcost[v]。

 

 

 

程序如下:

//

//  main.cpp

//  Prim

//

//  Created by duanqibo on 2019/7/3.

//  Copyright © 2019年 duanqibo. All rights reserved.

//  Prim普利姆算法建立最小生成樹

 

#include <iostream>

#include <stdio.h>

 

#define MaxVerNum 100

#define MaxValue 10000

typedef struct{

    char vexs[MaxVerNum];  //頂點集合

    int edges[MaxVerNum][MaxVerNum];  //邊集合

    int n,e;  //頂點和邊

}MGraph;

 

char vertex[]="0123456";

int nvertex=7,nedges=9;

int connection[][3]={{0,1,28},{0,5,10},{1,2,16},{1,6,14},{2,3,12},{3,4,22},{3,6,18},{4,5,25},{4,6,24}};

 

void CreateMgraph(MGraph &G)

{

    int i,j,k;

    G.n=nvertex;

    G.e=nedges;

    for(i=0;i<G.n;i++)

        G.vexs[i]=vertex[i];  //頂點

    for(i=0;i<G.n;i++)

        for(j=0;j<G.n;j++)

            G.edges[i][j]=MaxValue; //初始化邊最大值,沒有邊

    for(i=0;i<G.n;i++)

        G.edges[i][i]=0;  //初始化邊為0

    

    for(k=0;k<G.e;k++)

    {

        i=connection[k][0];

        j=connection[k][1];

        G.edges[i][j]=connection[k][2];

        G.edges[j][i]=G.edges[i][j]; //有向圖沒有這一行

    }

}

 

void printMgraph(MGraph &G)

{

    int i,j;

    printf("圖的結點總數:%d  邊總數:%d\n",G.n,G.e);

    for(i=0;i<G.n;i++)

    {

        for(j=0;j<G.n;j++)

            if(G.edges[i][j]==10000)

                printf("∞   "); //"00"代表無窮

            else

                printf("%d   ",G.edges[i][j]);

        printf("\n");

    }

}

 

//最小生成樹

typedef struct

{

    int head,tail,cost;

}MST[MaxVerNum];

 

void Prim(MGraph &G,MST &T,int u)

{

    int i,j;

    int *lowcost=new int[G.n];

    int *nearvex=new int[G.n];

    for(i=0;i<G.n;i++)

    {

        lowcost[i]=G.edges[u][i]; //u到各點的代價

        nearvex[i]=u;   //最短帶權路徑

    }

    nearvex[u]=-1;  //加入到生成樹頂點集合

    int k=0;

    for(i=0;i<G.n;i++)

        if(i!=u)

        {

            int min=MaxValue;

            int v=u;

            for(j=0;j<G.n;j++)

                if(nearvex[j]!=-1 && lowcost[j]<min) //=-1不參選

                {

                    v=j;

                    min=lowcost[j];//求生成樹外頂點到生成樹內頂點具有最小權值的邊,

                                   //v是當前具有最小權值的邊

                }

            if(v!=u)

            {

                T[k].tail=nearvex[v];

                T[k].head=v;

                T[k++].cost=lowcost[v];

                nearvex[v]=-1;  //該邊加入生成樹標記

                for(j=0;j<G.n;j++)

                    if(nearvex[j]!=-1 && G.edges[v][j]<lowcost[j])

                    {

                        lowcost[j]=G.edges[v][j];  //修改

                        nearvex[j]=v;

                    }

            }

            

        }//循環n-1次,加入n-1條邊

}

 

 

int main(int argc, const char * argv[]) {

    int i;

    MGraph g;

    CreateMgraph(g);

    printMgraph(g);

    MST t;

    Prim(g,t,0);

    printf("生成樹:結點->權值->結點\n");

    for(i=0;i<g.n;i++)

        printf("(%d)-->%d-->(%d)\n",t[i].tail,t[i].cost,t[i].head);

    return 1;

}

 運行結果如下: 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM