求最小生成树的两种方法

Posted aininot260

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求最小生成树的两种方法相关的知识,希望对你有一定的参考价值。

Kruskal算法核心是加边,先把所有边按照权值从小到大排序,然后在剩下的所有没有被选过的边中,找到最小的边,如果和已经选取的边构成回路则放弃,选取次小边,直到选取了n-1条边为止,这样所有点就都连通了。

每次从边集中选取的权值最小的边的两个顶点如果属于不同的树,就把他们合并(把这条边加入子图),反之则去看下一条边。

n个点e条边的情况下,时间复杂度O(e^2),并查集优化之后O(eloge),适用于求稀疏图的最小生成树。

int find(int x)
{
    return p[x]==x?x:p[x]=find(p[x]);
}

这是自带路径压缩的并查集

bool cmp(const int x,const int y)
{
    return w[x]<w[y];
}
    for(int i=1;i<=n;i++)
        p[i]=i;
    for(int i=1;i<=e;i++)
        r[i]=i;
    sort(r+1,r+e+1,cmp);

第一个for循环是让每个点自己独自成为一个集合

第二个for循环和sort是为了让所有边按照权重排序

之后的内容就很显然了,完整的代码如下,程序读入了点数n和每两个点之间的边权关系,输出了最小生成树的结果。

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=105;
 5 const int maxm=10005;
 6 int n;
 7 long long ans=0;
 8 //
 9 int e=0;
10 int u[maxm],v[maxm],w[maxm];
11 int p[maxn],r[maxm];
12 bool cmp(const int x,const int y)
13 {
14     return w[x]<w[y];
15 }
16 int find(int x)
17 {
18     return p[x]==x?x:p[x]=find(p[x]);
19 }
20 void kruskal()
21 {
22     for(int i=1;i<=n;i++)
23         p[i]=i;
24     for(int i=1;i<=e;i++)
25         r[i]=i;
26     sort(r+1,r+e+1,cmp);
27     for(int i=1;i<=e;i++)
28     {
29         int m=r[i];
30         int x=find(u[m]);
31         int y=find(v[m]);
32         if(x!=y)
33         {
34             ans+=w[m];
35             p[x]=y;
36         }
37     }
38 }
39 int main()
40 {
41     cin>>n;
42     for(int i=1;i<=n;i++)
43     for(int j=1;j<=n;j++)
44     {
45         e++;
46         u[e]=i,v[e]=j;
47         cin>>w[e];
48     }
49     kruskal();
50     cout<<ans<<endl;
51     return 0;
52 }

接下来我们介绍Prim算法,规定一个点集和一个边集,初始状态下点集中包含任意一个点,边集为空

然后重复一下操作直到点集中包含所有的点

在边集中选取权值最小的一条边<u,v>,并且满足u在当前点集中而v在其补集中,如果有多条边满足这个条件就取任意一条

将点v加入点集,<u,v>加入边集

最后我们通过最终的边集和点集描述最小生成树

对于时间复杂度来说,我写的好像是最第二种。。先粘在这里跑路了。。

技术分享图片

以后实现了相关细节再补充这部分内容,代码附下面。程序读入了n个点和m条边,输出了最小生成树的每一条边和边权之和。使用了邻接数组的数据结构。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 using namespace std;
  5 const int maxn=1005,maxm=1005;
  6 const int INF = 0x7fffffff;
  7 int n, m;
  8 int tot;
  9 struct point
 10 {
 11     bool vis;
 12     int t, w;
 13 };
 14 struct G
 15 {
 16     int cur;
 17     point e[maxm];
 18 }g[maxn];
 19 void addedge(int a,int b,int c)
 20 {
 21     tot++;
 22     point tmp;
 23     tmp.t = b;
 24     tmp.w = c;
 25     g[a].cur++;
 26     int t = g[a].cur;
 27     g[a].e[t] = tmp;
 28 }
 29 // 
 30 int vis[maxn];
 31 int fa[maxn];
 32 int dis[maxn];
 33 int tot1;
 34 int b1[maxn];
 35 int b2[maxn];
 36 int ans;
 37 //
 38 void prim()
 39 {
 40     memset(vis,0,sizeof(vis));
 41     int cnt=0;
 42     int p=1;
 43     for (int i=1;i<=n;i++)
 44         fa[i] = p;
 45     vis[p] = 1;
 46     cnt++;
 47     for(int i=1;i<=n;i++)
 48     {
 49         for (int tmp=1;tmp<=g[p].cur;tmp++)
 50         {
 51             if(g[p].e[tmp].t==i)
 52             dis[i]=g[p].e[tmp].w;
 53         }
 54         if(dis[i]==0)
 55             dis[i]=INF;
 56     }
 57     while(cnt!=n)
 58     {
 59         int l = INF;
 60         int q;
 61         for(int i=1;i<=n;i++)
 62         {
 63             if(l>dis[i]&&!vis[i])
 64             {
 65                 l=dis[i];
 66                 q=i;
 67             }
 68         }
 69         vis[q]=true;
 70         p=q;
 71         if(l!=INF)
 72         {
 73             tot1++;
 74             b1[tot1]=min(p,fa[p]);
 75             b2[tot1]=max(p,fa[p]);
 76         }
 77         cnt++;
 78         ans+=l;
 79         for(int i=1;i<=n;i++)
 80         if(!vis[i])
 81         {
 82             int t=INF;
 83             for (int tmp=1;tmp<=g[p].cur;tmp++)
 84             {
 85                 if(g[p].e[tmp].t==i)
 86                 t=g[p].e[tmp].w;
 87             }
 88             if(dis[i]>t)
 89             {
 90                 dis[i]=t;
 91                 fa[i]=p;
 92             }
 93         }
 94     }
 95 }
 96 int main()
 97 {
 98     cin>>n>>m;
 99     for(int i=1;i<=m;i++)
100     {
101         int a,b,c;
102         cin>>a>>b>>c;
103         addedge(a,b,c);
104         addedge(b,a,c);
105     }
106     prim();
107     cout<<tot1<<endl;
108     for(int i=1;i<=tot1;i++)
109         cout<<i<<":"<<b1[i]<<" "<<b2[i]<<endl;
110     cout << ans << endl;
111     return 0;
112 }

 

以上是关于求最小生成树的两种方法的主要内容,如果未能解决你的问题,请参考以下文章

对最小生成树的两种算法感悟

最小生成树的两种方法(Kruskal算法和Prim算法)

次最小生成树 模版

最小生成树的问题----数据结构

急求KRUSKAL算法求最小生成树过程演示

欧几里德 平面最小生成树算法