把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

模板:最小生成树(MST)

https://www.luogu.org/problemnew/show/P3366

 

Kruskal算法 O(E*logE)
1. 所有的边从小到大排序
2. 初始状态下每个结点都是独立的集合
3. 枚举每一条边e
4. 如果边的两个端点u、 v属两个不同的集合,
把这条边加入MST, 否则跳过。
排序
贪心选择
并查集

用并查集优化后的总时间复杂度为(mlogm+ma(n)),a(n)是一次并查集的复杂度

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 struct Edge{
 6     int u, v, w;
 7 }edge[200005];
 8 int f[5005], n, m, ans, eu, ev, cnt;
 9 inline bool cmp(Edge a,Edge b){ 
10     return a.w<b.w; 
11 }
12 inline int find(int x){
13     while(x!=f[x]) x=f[x]=f[f[x]];
14     return x;
15 }
16 int main(){
17     scanf("%d%d",&n,&m);
18     for(int i=1; i<=n; i++) f[i]=i;
19     for(int i=0; i<m; i++)
20         scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
21     sort(edge, edge+m, cmp);
22     for(int i=0; i<m; i++){
23         eu=find(edge[i].u);
24         ev=find(edge[i].v);
25         if(eu==ev) continue;
26         ans+=edge[i].w;
27         f[ev]=eu; 
28         cnt++;
29         if(cnt==n-1) break;
30     }
31     printf("%d",ans);
32     return 0;
33 }

 

 Prim算法 O(N^2)
加点法, 每次选择代价最小的边对应的点,
加入到最小生成树中。
算法从某一个顶点s开始, 逐渐长大覆盖整
个连通网的所有顶点。
1. 图顶点集合为V; 初始集合u={s},v=V-u
2. 在两个集合u,v能够组成的边中, 选择一条
代价最小的边(u0,v0), 加入到最小生成树
中, 并把v0并入到集合u中。
3. 重复上述步骤, 直到最小生成树有n-1条边
或者n个顶点为止。

此处使用堆优化的的prim,每次选取最小值的时间复杂度为O(logm),总时间复杂度为O((n+m)logm).

 1 #include<cstdio>
 2 #include<queue>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef pair <int,int> pii;
 7 int k, n, m, cnt, sum,x, y, z;
 8 int h[5005], dis[5005], vis[5005];
 9 struct Edge{
10     int v, w, next;//边的右端点, 边权, 下一条边的编号 
11 }e[400005];
12 void add(int u,int v,int w){
13     e[++k].v=v;
14     e[k].w=w;
15     e[k].next=h[u];
16     h[u]=k;
17 }
18 priority_queue <pii,vector<pii>,greater<pii> > q;//第一维数值,第二维节点编号 
19 void prim(){
20     dis[1]=0;
21     q.push(make_pair(0,1));
22     while(!q.empty() && cnt<n){
23         int d=q.top().first, u=q.top().second;
24         q.pop();
25         if(vis[u]) continue;
26         cnt++;
27         sum+=d;
28         vis[u]=1;
29         for(int i=h[u]; i!=-1; i=e[i].next)
30             if(e[i].w<dis[e[i].v]){ 
31                 dis[e[i].v]=e[i].w;
32                 q.push(make_pair(dis[e[i].v],e[i].v));
33             } 
34     }
35 }
36 int main(){
37     memset(dis,0x3f,sizeof(dis));
38     memset(h,-1,sizeof(h));
39     scanf("%d%d",&n,&m);
40     for(int i=1; i<=m; i++){
41         scanf("%d%d%d",&x,&y,&z);
42         add(x,y,z);
43         add(y,x,z);
44     }
45     prim();
46     if(cnt==n)    printf("%d",sum);
47     else         printf("orz");
48     return 0;
49 }

 

posted @ 2018-07-19 18:59  AZe-qwq  阅读(247)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end