要了解最小生成树的概念,我们首先要知道生成树是什么

生成树的定义

一个有 n 个结点的联通图的生成树是原图的极小连通子图,生成树包含原图中的所有 n 个结点,并且有保持图连通的最少的边。

最小生成树的性质

1.容易想象,要保证n个节点联通,至少要有n-1条边,所以一个有n个节点的生成树必有n-1条边。

2. 在所有生成树中,最小生成树的权值之和是最小的。

3. 再添加任意一条边,都将造成回路。

MST性质

描述:假设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集。若(u,v)是一条具有最小权值(代价)的边,其中u∈U,v∈V-U,则必存在一棵包含边(u,v)的最小生成树。

MST算法告诉我们,可以通过不断确定最小权值的边来获取最小生成树。下面介绍两种根据MST性质,构造最小生成树的算法。

Prim算法

Prim算法的指导思想是通过不断选择点来构建生成树。设图N = {V,{E}},用集合U来表示生成树的顶点的集合,一开始,U为空集。将V任意一个点添加到U中,然后重复以下操作

1. 从未加入U的顶点,即V-U中,选择出距离U最近的顶点。这里的距离指的是V-U中一个顶点和U中所有顶点距离的最小值。

2. 将该顶点加入到U中,同时更新其他未加入U的顶点到U的最短距离。

3. 如果V中所有顶点都加入U则停止,否则返回步骤1。

Prim算法是从一个顶点集合不断扩展,按照边的权重大小选择加入这个集合的点。

代码实现

 

#include<iostream>
#include<vector>
using namespace std;
const int inf = 1e9+5;
int Edge[1005][1005];  // 用邻接矩阵来表示图
int n,m;
int dist[1005];  //用来记录到顶点集合U的距离
vector<bool>vis(1005,false);
//Prim算法
int Prim()
{
    int sum = 0;
    fill(dist,dist+1005,inf);
    dist[1] = 0;  // 将0加入到U中
    for(int i=1;i<=n;i++)
    {
        int mindist = inf,k;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&mindist>dist[j])
            {
                k = j;
                mindist = dist[j];
            }
        }
        vis[k] = 1;
        sum +=dist[k];
        printf("Choose the vertex:%d\n",k);
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&Edge[k][j]<dist[j])
            {
                dist[j] = Edge[k][j];
            }
        }
    }
    return sum;
}

int main()
{
    scanf("%d %d",&n,&m);
    int s,e,v;// 构件图
    fill(Edge[0],Edge[0]+1005*105,inf);
    for(int i=0;i<m;i++)
    {
        scanf("%d %d %d",&s,&e,&v);
        Edge[s][e] = Edge[e][s] = v;
    }
    int sum = Prim();
    printf("The sum of MST:%d\n",sum);
    return 0;
}

 

 

 

 

  

 

 

Kruskal算法

Kruskal的指导思想是将,通过不断选择边来构建生成树。设图N={V,{E}},V中有顶点n个,则初始化n个集合,U1={V1},U2={V2},...,Un={Vn},然后进行如下操作:

1. 从{E}中选择端点在不同集合中权值最小的边。

2. 合并这两个边所在的集合。

3. 如果所有集合都合并为一个集合则停止,否则返回步骤1。

 Kruskal算法是将原有的顶点集合按照边的权重大小不断合并,最终形成现有的集合。

代码实现:

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 int n,m;
 5 struct Edge{
 6     int s,t,v;
 7     Edge(int s,int t,int v):s(s),t(t),v(v)
 8     {
 9     }
10     Edge(){}
11     bool operator<(const Edge&a)
12     {
13         return v<a.v;
14     }
15 }E[1005*1005];
16 int pre[1005];
17 void init()
18 {
19     for(int i=1;i<=n;i++)
20         pre[i] = i;
21 }
22 int find_pre(int x)
23 {
24     if(x==pre[x])
25         return x;
26     else
27         return pre[x] = find_pre(pre[x]);
28 }
29 void Union(int x,int y)
30 {
31     int rootx = find_pre(x),rooty = find_pre(y);
32     if(rootx!=rooty)
33         pre[rootx] = rooty;
34 }
35 int main()
36 {
37     scanf("%d %d",&n,&m);
38     init();
39     int s,t,v;
40     for(int i=0;i<m;i++)
41     {
42         scanf("%d %d %d",&s,&t,&v);
43         E[i] = Edge(s,t,v);
44     }
45     sort(E,E+m);
46     int cnt = 0,sum = 0;
47     for(int i=0;i<m;i++)
48     {
49         if(find_pre(E[i].s)!=find_pre(E[i].t))
50         {
51             printf("Choose the edge: %d %d\n",E[i].s,E[i].t);
52             Union(E[i].s,E[i].t);
53             cnt++;
54             sum+=E[i].v;
55         }
56         if(cnt==n-1)
57             break;
58     }
59     printf("The sum of MST:%d",sum);
60     return 0;
61 }