图论:Prim算法 求最小生成树

Prim算法 求最小生成树
 
  利用了蓝白点思想,先将所有点标记为蓝点。用一个数组布尔数组b 标记点的蓝白,如果为true就是蓝点,否则是白点。先定义一个整型变量mst=0,mst就是最小生成树。然后用一个二维数组w 记录 边i和边j之间的权值,再用一个一维数组mins 记录的是蓝点的最小边权,这个mins数组是关键。
  int w[51][51];//边的权值
  int mins[51];//蓝点的最小边权
  bool b[51];//蓝点标记
  int mst = 0;//最小生成树的边权和

 

  然后将所有点都初始化为蓝点,并且将每个点的最小边权先初始化为无穷大,因为是求最小生成树。

for (int i = 0; i <= n; ++i)
    {
        mins[i] = oo;//最小边权初始化为最大
        b[i] = true;//全部初始化为蓝点
    }//i等于0的点要初始化 方便后面每次比较找到一个最小的蓝点

 

  然后先初始化所有点的边权为无穷大,然后再输入边权,这样两个点之间有边相连就有边权,否则两个点之间的边权就是无穷大。

for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            w[i][j] = oo;//先初始化边的权值为无穷
    int x, y, z;
    for (int i = 1; i <= m; ++i)
    {
        cin >> x >> y >> z;
        w[x][y] = w[y][x] = z;//存储权值
    }

  

  然后任选一个点开始,开始的点就把它的最小边权设为0,初始化mins[开始点]=0,我们一般选1为起点。

 mins[1] = 0;//任选一点开始

  

  然后就要一个外层循环,循环n个点,每次循环都要选出一个边权最小的蓝点,所以要再加一个内层循环寻找mins值最小的点,把最小边权加入mst,就相当于把这条边加入了最小生成树,因为第一次mins[1]=0,所以第一次相当于不加入边,所以一共加入n-1条边,刚好是最小生成树的边数,并且更新所有与选出的蓝点邻接的蓝点的最小边权mins值,因为更新,所以要再内层并列一个内层循环,遍历所有邻接的蓝点,更新的转移方程就是用蓝点和邻接点的蓝点的边权代替mins[邻接点],但前提是边权要更小才能更新。注意每次选出来蓝点后要把蓝点洗白,避免重复选。

  

for (int i = 1; i <= n; ++i)
    {
        //找到mins[k]值最小的蓝点
        int k = 0;//初始化一个比较的点
        for (int j = 1; j <= n; ++j)
            if (b[j] && mins[j] < mins[k])
                k=j;//替换之
        b[k] = 0;//洗白找到的蓝点
        mst += mins[k];//累加生成树权值

        //修改与找到的蓝点k相连的所有蓝点
        for (int j = 1; j <= n; ++j)//枚举所有点
        {
            if (b[j] && w[k][j] < mins[j])
                mins[j] = w[k][j];
        }

    }

  

  完整代码:

 1 #include<iostream>
 2 using namespace std;
 3 int w[51][51];//边的权值
 4 int mins[51];//蓝点的最小边权
 5 bool b[51];//蓝点标记
 6 int mst = 0;//最小生成树的边权和
 7 int main()
 8 {
 9     int n, m;//n个点 m条边
10     cin >> n >> m;
11     int oo = 0x7fffff;
12     for (int i = 1; i <= n; ++i)
13         for (int j = 1; j <= n; ++j)
14             w[i][j] = oo;//先初始化边的权值为无穷
15     int x, y, z;
16     for (int i = 1; i <= m; ++i)
17     {
18         cin >> x >> y >> z;
19         w[x][y] = w[y][x] = z;//存储权值
20     }
21     for (int i = 0; i <= n; ++i)
22     {
23         mins[i] = oo;//最小边权初始化为最大
24         b[i] = true;//全部初始化为蓝点
25     }//i等于0的点要初始化 方便后面每次比较找到一个最小的蓝点
26     mins[1] = 0;//任选一点开始
27     for (int i = 1; i <= n; ++i)
28     {
29         //找到mins[k]值最小的蓝点
30         int k = 0;//初始化一个比较的点
31         for (int j = 1; j <= n; ++j)
32             if (b[j] && mins[j] < mins[k])
33                 k=j;//替换之
34         b[k] = 0;//洗白找到的蓝点
35         mst += mins[k];//累加生成树权值
36 
37         //修改与找到的蓝点k相连的所有蓝点
38         for (int j = 1; j <= n; ++j)//枚举所有点
39         {
40             if (b[j] && w[k][j] < mins[j])
41                 mins[j] = w[k][j];
42         }
43 
44     }
45     cout << mst;
46     return 0;
47 }

 

  

 

posted @ 2022-05-10 15:32  朱朱成  阅读(54)  评论(0编辑  收藏  举报