最小生成树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;
}

在这里感激志权师兄的教导!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值