最小生成树初步

对于最小生成树,小白书上提供了prime算法与克鲁斯卡尔算法。

相比较而言,个人认为克鲁斯卡尔要优于prime,并且更加好理解一些(而且一看名字的逼格就很高,五个字的算法好像听起来都很厉害的样子。)

如果执意要用prime算法,出门右转,这篇笔记不用看了。

克鲁斯卡尔的核心思想就是以图的边为基础,没错是"边"!不要用"点"。

不过就是储存每条边的权值,然后快排一波,按照边来判断两个端点是否在同一个集合中,这里就要用到并查集的father()函数了。如果不在同一集合中,就将两个点的祖先结点连成一个树,并在总和上加上这条边的权值。

来波代码……

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 struct sd{
 6     int x,y,w;
 7 };
 8 //注意用结构体来存边。
 9 sd a[100005];
10 int f[100005];
11 bool cmp(sd a,sd b)
12 {
13     return a.w<b.w;
14 }
15 int father(int v)
16 {
17     if(f[v]!=v)f[v]=father(f[v]);
18     return f[v];
19 }
20 //牛逼的father()函数。
21 int main()
22 {
23     int n,m=0;
24     scanf("%d",&n);
25     for(int i=1;i<=n;i++)
26         for(int j=1;j<=n;j++)
27         {
28             int x;
29             scanf("%d",&x);
30             if(x!=0)
31             {
32                 m++;
33                 a[m].x=i;a[m].y=j;a[m].w=x;
34             }
35         }
36     //注意!!!此种读入方法是按照邻接矩阵来读入,
37     //也可以用“端点1,端点2,边权”的方式读入
38     for(int i=1;i<=n;i++)
39     f[i]=i;
40     int tot=0;
41     sort(a+1,a+1+m,cmp);//快排一波
42     for(int i=1;i<=m;i++)
43     {
44         int fx=father(a[i].x);
45         int fy=father(a[i].y);//找祖先。
46         if(fx!=fy)//判断是否有公共祖先,即是否在同一集合中。
47         {
48             f[fx]=fy;
49             tot=tot+a[i].w;//加上权值。
50         }
51     }
52     printf("%d",tot);
53     return 0;
54 }

上面是一个模板。

下面来两道基础的例题,可供新手练习。

先来一道基础题

http://ybt.ssoier.cn:8088/problem_show.php?pid=1391

稍稍升级的一道题目

http://ybt.ssoier.cn:8088/problem_show.php?pid=1393

 接着一道有趣的让我有点懵的多个最小生成树,仔细想想其实根本不难,只有小改。

https://www.luogu.org/problem/show?pid=1195

再来一波

https://www.luogu.org/problem/show?pid=1194

原文地址:https://www.cnblogs.com/genius777/p/8470358.html