码迷,mamicode.com
首页 > 其他好文 > 详细

(模板)最小生成树

时间:2019-01-31 00:14:26      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:mem   names   lse   最小   忽略   strong   无向图   continue   --   

2019-01-30

最小生成树基本算法

定义

给定一个边带权的无向图G=(V,E),n=|V|,m=|E|,由V中全部n个定点和E中n-1条边构成的无向连通子图被称为G的一颗生成树。

边的权值之和最小的生成树被称为无向图G的最小生成树。(Minimun Spanning Tree,MST).

定理

任意一颗最小生成树一定包含无向图中权值最小的边

证明:

假设最小的边z不在MST上,将其加入树中,可构成一个环,并且环上所有边权都比z大,因此用z代表任意一条边,所得的生成树都一定会比原来更小。假设不成立。

Kruskal:
桉边权排序,然后依次扫描每个边(x,y,z),若x,y属于同一个集合,则忽略这条边,否则合并x,y所在的集合,将z累加到答案中。---O(mlogm)

代码:

 

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 struct rec{
 6     int x,y,z;
 7 }e[200010];
 8 
 9 int cmp(rec a,rec b){
10     return a.z<b.z;
11 }
12 int fa[5010],n,m,ans=0;
13 
14 int get(int x){
15     if(x==fa[x])        return x;
16     return fa[x]=get(fa[x]);
17 }
18 
19 int main(){
20     scanf("%d%d",&n,&m);
21     for(int i=1 ; i<=m ; i++)
22         scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
23     sort(e+1,e+1+m,cmp);
24     for(int i=1 ; i<=n ; i++)    fa[i]=i;
25     
26     for(int i=1 ; i<=m ; i++){
27         int x=get(e[i].x);
28         int y=get(e[i].y);
29         if(x==y)    continue;
30         fa[x]=y;
31         ans+=e[i].z;
32     }
33     printf("%d\n",ans);    
34     return 0; 
35 }

 

 

 

Prim

任一时刻,设已经确定属于最小生成树的节点集合为T,剩余点集合为S,找到minx€S,y€T 即两个端点分别属于S和T的权值最小的边,然后把点x从集合S中删除,加入集合T,并把该边边权累加到答案中。

具体来说,就是一个维护数组d[x]:  当x未被选中时,表示x与S中的节点间权值最小的边的权值。 若x已被选中,表示 x被选中加入已选集合时选中的最小边的权值。

遍历1~n-1每个点,每次选出T中d[]最小的点加入集合S,然后更新T中其它点的d值---O(n^2),

代码:

 

 1 const int N=3010;
 2 int a[N][N],d[N],n,m,ans;
 3 bool v[N];
 4 
 5 void prim()
 6 {
 7     memset(d,0x3f,sizeof(d));
 8     memset(v,0,sizeof(v));
 9     d[1]=0;
10     for(int i=1 ; i<n ; i++)
11     {
12         int x(0);
13         for(int j=1 ; j<=n ; j++)
14             if(!v[j]&&d[j]<d[x]) x=j;
15         v[x]=1;
16         for(int y=1 ; y<=n ; y++)
17             if(!v[y])
18                 d[y]=min(d[y],d[x]+a[x][y]);
19     }
20 }
21 
22 int main()
23 {
24     prim();
25     for(int i=2 ; i<=n ; i++)     ans+=d[i];
26 }

 Prim优先队列优化---O(mlogn)

 1 #include<bits/stdc++.h>
 2 #define INF 0x7f7ff
 3 using namespace std;
 4 int n,m,dist[5010],head[5010],k,ans,tot;
 5 bool vis[5010];
 6 struct node
 7 {
 8     int to,next,w;
 9 }edge[400010];
10 struct p
11 {
12     int id,d;
13     bool operator < (const p &a) const
14     {
15         return a.d<d;
16     }
17 };
18 void add(int u,int v,int w)
19 {
20     edge[++k].to=v;
21     edge[k].w=w;
22     edge[k].next=head[u];
23     head[u]=k;
24 }
25 void Prim()
26 {
27     fill(dist+1,dist+1+n,INF);
28     priority_queue<p> q;
29     p now;
30     now.id=1;now.d=dist[1]=0;
31     q.push(now);
32     while(!q.empty())
33     {
34         p now=q.top();q.pop();
35         int u=now.id;
36         if(now.d!=dist[u]) continue;
37         vis[u]=1;
38         ans+=dist[u];
39         tot++;
40         for(int i=head[u];i;i=edge[i].next)
41         {
42             int v=edge[i].to;
43             if(!vis[v]&&dist[v]>edge[i].w)
44             {
45                 dist[v]=edge[i].w;
46                 p nxt;
47                 nxt.d=dist[v];
48                 nxt.id=v;
49                 q.push(nxt);
50             }
51         }
52     }
53     if(tot<n) ans=-1;
54 }
55 int main()
56 {
57 //    std::ios::sync_with_stdio(false);
58     cin>>n>>m;
59     for(int i=1;i<=m;i++)
60     {
61         int a,b,c;
62         cin>>a>>b>>c;
63         add(a,b,c);
64         add(b,a,c);
65     }
66     Prim();
67     if(ans==-1) cout<<"orz"<<endl;
68     else cout<<ans;
69 }

 

(模板)最小生成树

标签:mem   names   lse   最小   忽略   strong   无向图   continue   --   

原文地址:https://www.cnblogs.com/wmq12138/p/10340197.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!