最小生成樹Prim算法

轉自http://www.cnblogs.com/Veegin/archive/2011/04/29/2032388.html


今天從志權師兄那裏學會了最小生成樹。所謂生成樹,就是n個點之間連成n-1條邊的圖形。而最小生成樹,就是權值(兩點間直線的值)之和的最小值。

  

         首先,要用二維數組記錄點和權值。如上圖所示無向圖:

int map[7][7];
       map[1][2]=map[2][1]=4;
       map[1][3]=map[3][1]=2;
       ......

      然後再求最小生成樹。具體方法是:

1.先選取一個點作起始點,然後選擇它鄰近的權值最小的點(如果有多個與其相連的相同最小權值的點,隨便選取一個)。

如1作爲起點。

visited[1]=1;//標記點1,表明頂點1已加入最小生成樹

pos=1;

//用low[]數組不斷刷新最小權值,low[i](0<i<=點數)的值爲:i點到鄰近點(未被標記)的最小距離。

low[1]=0;  //起始點i到鄰近點的最小距離爲0

low[2]=map[pos][2]=4;

low[3]=map[pos][3]=2;

low[4]==map[pos][4]=3;

low[5]=map[pos][5]=MaxInt;  //無法直達

low[6]=map[pos][6]=MaxInt;

 

  2.再在伸延的點找與它鄰近的兩者權值最小的點。

//low[]以3作當前位置進行更新

visited[3]=1;//標記點3

pos=3;

low[1]=0;   //已標記,不更新

low[2]=map[1][2]=4;  //比5小,不更新

low[3]=2;  //已標記,不更新

low[4]=map[1][4]=3;   //比1大,更新後爲:low[4]=map[3][4]=1;

low[5]=map[1][5]=MaxInt;//無法直達,不更新

low[6]=map[1][6]=MaxInt;//比2大,更新後爲:low[6]=map[3][6]=2;

 

    3.如此類推...

 
 
     當所有點都連同後,結果最生成樹如上圖所示。

     所有權值相加就是最小生成樹,其值爲2+1+2+4+3=12。

     至於具體代碼如何實現,現在結合POJ1258例題解釋。代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <string.h>
#define MaxInt 65535
#define N 110
//創建map二維數組儲存圖表,low數組記錄每2個點間最小權值,visited數組標記某點是否已訪問
int map[N][N],low[N],visited[N];
int n;
 
int prim()
{
    int i,j,pos,min,result=0;
    memset(visited,0,sizeof(visited));
//從某點開始,分別標記和記錄該點
    visited[1]=1;pos=1;
//第一次給low數組賦值
    for(i=1;i<=n;i++)
        if(i!=pos) low[i]=map[pos][i];
//再運行n-1次
    for(i=1;i<n;i++)
    {
//找出最小權值並記錄位置
     min=MaxInt;
     for(j=1;j<=n;j++)
         if(visited[j]==0&&min>low[j])//如果還沒有訪問過,並且權值小於最小權值
         {
             min=low[j];
     pos=j;
         }
//最小權值累加
    result+=min;
//標記該點
    visited[pos]=1;
//更新權值
    for(j=1;j<=n;j++)
        if(visited[j]==0&&low[j]>map[pos][j])
            low[j]=map[pos][j];
    }
    return result;
}
 
int main()
{
    int i,v,j,ans;
    while(scanf("%d",&n)!=EOF)
    {
//所有權值初始化爲最大
        memset(map,MaxInt,sizeof(map));
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
            {
                scanf("%d",&v);
                map[i][j]=map[i][j]=v;
            }
            ans=prim();
            printf("%d\n",ans);
    }
    return 0;
}

在這裏感激志權師兄的教導!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章