最小生成樹的PRIM算法(c++實現)


  在網絡搭建中,最小生成樹有其廣泛的應用.本文是作者學習了PRIM算法實現最小生成樹之后的筆記體會.歡迎指正批評.

 

1.概述

  設G =(V,E)是無向連通帶權圖,即一個網絡。E中每條邊(v,w)的權為c[v][w]。如果G的子圖G’是一棵包含G的所有頂點的樹,則稱G’為G的生成樹。生成樹上各邊權的總和稱為該生成樹的耗費。在G的所有生成樹中,耗費最小的生成樹稱為G的最小生成樹

     網絡的最小生成樹在實際中有廣泛應用。例如,在設計通信網絡時,用圖的頂點表示城市,用邊(v,w)的權c[v][w]表示建立城市v和城市w之間的通信線路所需的費用,則最小生成樹就給出了建立通信網絡的最經濟的方案。

  最小生成樹性質:

   設G=(V,E)是連通帶權圖,U是V的真子集。如果(u,v)屬於E,且u屬於U,v屬於V-U,且在所有這樣的邊中,(u,v)的權c[u][v]最小,那么一定存在G的一棵最小生成樹,它以(u,v)為其中一條邊。這個性質有時也稱為MST性質。

 

2.PRIM算法

  設G=(V,E)是連通帶權圖,V={1,2,…,n}。

  構造G的最小生成樹的Prim算法的基本思想是:首先置S={1},然后,只要S是V的真子集,就作如下的貪心選擇:選取滿足條件i屬於S,j屬於V-S,且c[i][j]最小的邊,將頂點j添加到S中。這個過程一直進行到S=V時為止。

  在這個過程中選取到的所有邊恰好構成G的一棵最小生成樹。

  利用最小生成樹性質和數學歸納法容易證明,上述算法中的邊集合T始終包含G的某棵最小生成樹中的邊。因此,在算法結束時,T中的所有邊構成G的一棵最小生成樹。

  例如,對於右圖中的帶權圖,按Prim算法選取邊的過程如下頁圖所示。  

按Prim算法選取邊的過程如下頁圖所示。

  在上述Prim算法中,還應當考慮如何有效地找出滿足條件i在S中,j也在V-S中,且權c[i][j]最小的邊(i,j)。實現這個目的的較簡單的辦法是設置2個數組closest和lowcost。

  在Prim算法執行過程中,先找出V-S中使lowcost值最小的頂點j,然后根據數組closest選取邊(j,closest[j]),最后將j添加到S中,並對closest和lowcost作必要的修改。

  用這個辦法實現的Prim算法所需的計算時間為O(n2).

 

以下是我參考<計算機算法分析與設計>王曉東第三版的代碼設計的程序.

#include <iostream>
#define MAXINT 6

using namespace std;

//聲明一個二維數組,C[i][j]存儲的是點i到點j的邊的權值,如果不可達,則用1000表示
//借此二維數組來表示一個連通帶權圖
int c[MAXINT][MAXINT]={{1000,6,1,5,1000,1000},{6,1000,5,1000,3,1000},{1,5,1000,5,6,4},{5,1000,5,1000,1000,2},{1000,3,6,1000,1000,6},{1000,1000,4,2,6,1000}};
void Prim(int n)
{
    int lowcost[MAXINT];//存儲S中到達對應的其它各點的最小權值分別是多少
    int closest[MAXINT];//closest[]數組保存的是未在S中的點所到達S中包含的最近的點是哪一個,如:closest[i]=1表示i最靠近的S中的點是1
    bool s[MAXINT];//bool型變量的S數組表示i是否已經包括在S中
    int i,k;
    s[0]=true;//從第一個結點開始尋找,擴展
    for(i=1;i<=n;i++)//簡單初始化
    {
        lowcost[i]=c[0][i];
        closest[i]=0;//現在所有的點對應的已經在S中的最近的點是1
        s[i]=false;
    }
    cout<<"0->";
    for(i=0;i<n;i++)
    {
        int min=1000;//最小值,設大一點的值,后面用來記錄lowcost數組中的最小值
        int j=1;
        for(k=1;k<=n;k++)//尋找lowcost中的最小值
        {
            if((lowcost[k]<min)&&(!s[k]))
            {
                min=lowcost[k];j=k;
            }
        }
        cout<<j<<" "<<"->";
        s[j]=true;//添加點j到集合S中
        for(k=1;k<=n;k++)//因為新加入了j點,所以要查找新加入的j點到未在S中的點K中的權值是不是可以因此更小
        {
            if((c[j][k]<lowcost[k])&&(!s[k])){lowcost[k]=c[j][k];closest[k]=j;}
        }
    }

}
int main()
{
    
    //輸入初始化數組

    cout<<"請輸入初始權值數組:"<<endl;
    for(int i=0;i<MAXINT;i++)
    {
        for(int j=0;j<MAXINT;j++)
        {
        //    cout<<"please enter c["<<i<<"]["<<j<<"]:";
        //    cin>>c[i][j];
            cout<<c[i][j]<<"\t";
        //    cout<<endl;
        }
        cout<<endl;
    }
    
    Prim(MAXINT-1);
    return 0;




}

 

 

 

 

 

 

  


免責聲明!

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



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