标签: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