求最小生成树的两种方法

匿名 (未验证) 提交于 2019-12-03 00:40:02

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 }

原文:https://www.cnblogs.com/aininot260/p/9272844.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!