嗯...

理解生成树的概念:

在一幅图中将所有n个点连接起来的n-1条边所形成的树。

最小生成树:

边权之和最小的生成树。

最小瓶颈生成树:

对于带权图,最大权值最小的生成树。

如何操作?

1.Prim算法(O(mlogn))

2.Kruskal算法(O(mlogn))

推荐使用第二种,无需建图。

算法流程:

Prim算法:(思想类似dijkstra)

  随意选取一个点作为已访问集合的第一个点,并将所有相连的边加入堆中
  从堆中找到最小的连接集合内和集合外点的边,将边加入最小生成树中
  将集合外点标记为已访问,并将相连边加入堆
  重复以上过程直到所有点都在访问集合中

Kruskal算法:(并查集思想)

  将边按照权值排序
  依次枚举每一条边,若连接的两点不连通则加入最小生成树中
  使用并查集维护连通性

模板代码:

 int f[], h;
struct node{
int x, y, l;
} a[];
inline bool cmp(node i, node j){
return i.l < j.l;
}
inline int find(int x){
if(x != f[x])//本身是否为父亲节点
f[x] = find(f[x]);
return f[x];
}//并查集操作
int main(){
for(int i = ; i <= n; i++){
f[i] = i;
}//父节点初始化
sort(a+, a+k+, cmp);//排序
for(int i = ; i <= k; i++){
int r1 = find(a[i].x);
int r2 = find(a[i].y);
if(r1 != r2){
f[r1] = r2;
}
}
}

Kruskal

#include<bits/stdc++.h>
using namespace std;
int n,m,a,b,c;
int sum;
int g[][],minn[];
bool u[];
int main(){
memset(g,0x7f,sizeof(g));
memset(minn,0x7f,sizeof(minn));
memset(u,true,sizeof(u));
cin>>n>>m;
for(int i=;i<=m;i++)
{
cin>>a>>b>>c;
g[a][b]=g[b][a]=c;
sum+=c;
}
minn[]=;
for(int i=;i<=n;i++){
int k=;
for(int j=;j<=n;j++)
if(u[j]&&minn[j]<minn[k])
k=j;
u[k]=false;
for(int j=;j<=n;j++)
if(u[j]&&g[k][j]<minn[j])
minn[j]=g[k][j];
}
int total=;
for(int i=;i<=n;i++)
total+=minn[i];
cout<<sum-total<<endl;
return ;
}

Prim


模板题:

洛谷P3366【模板】最小生成树:

题目链接:https://www.luogu.org/problemnew/show/P3366

思路:(Kruskal)

一道模板题,首先用一个结构体读入,然后初始化父节点,再按边权排序,然后用find函数分别找输入时的两个点的父节点,并判断其中一个是否是另一个的父亲,否则就进行合并,并将h+=a[i].l。(思路比较好理解)

 #include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; int h, f[]; struct node{
int x, y, l;
} a[]; inline bool cmp(node i, node j){
return i.l < j.l;
} inline int find(int x){
if(x != f[x])
f[x] = find(f[x]);
return f[x];
} int main(){
int n, m;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++){
f[i] = i;
}
for(int i = ; i <= m; i++){
scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].l);
//h += a[i].l;
}
sort(a+, a+m+, cmp);
for(int i = ; i <= m; i++){
int r1 = find(a[i].x);
int r2 = find(a[i].y);
if(r1 != r2){
f[r1] = r2;
h += a[i].l;
//h -= a[i].l;
}
}
printf("%d", h);
return ;
}

AC代码


洛谷P2820 局域网:

题目链接:https://www.luogu.org/problemnew/show/P2820

思路:

首先这道题的问法就很模板:

很显然“f(i,j)表示i,j之间连接的畅通程度”即为i到j点的权值;“除去一些连线,使得网络中没有回路,并且被除去网线的Σf(i,j)最大”很显然是求最小生成树。但注意一个细节,它与最小生成树有所不同,它要求的是Σf(i,j)最大。

所以我们在最小生成树的模板上进行修改即可:读入时将所有的边权都加到h中。在判断父节点是否相同时,若不同,则将合并,并将合并的这条边的权值减掉即可。

 #include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; int f[], h; struct node{
int x, y, l;
} a[]; inline bool cmp(node i, node j){
return i.l < j.l;
} inline int find(int x){
if(x != f[x])
f[x] = find(f[x]);
return f[x];
} int main(){
int n, k;
scanf("%d%d", &n, &k);
for(int i = ; i <= n; i++){
f[i] = i;
}
for(int i = ; i <= k; i++){
scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].l);
h += a[i].l;
}
sort(a+, a+k+, cmp);
for(int i = ; i <= k; i++){
int r1 = find(a[i].x);
int r2 = find(a[i].y);
if(r1 != r2){
f[r1] = r2;
h -= a[i].l;
}
}
printf("%d", h);
return ;
}

AC代码


大概就是这样,个人认为Kruskal算法比Prim算法写起来简单并好理解....

最小生成树 & 洛谷P3366【模板】最小生成树 & 洛谷P2820 局域网的更多相关文章

  1. [洛谷P3366] [模板] 最小生成树

    存个模板,顺便复习一下kruskal和prim. 题目传送门 kruskal 稀疏图上表现更优. 设点数为n,边数为m. 复杂度:O(mlogm). 先对所有边按照边权排序,初始化并查集的信息. 然后 ...

  2. P3366 (模板)最小生成树

    2019-01-30 最小生成树基本算法 定义: 给定一个边带权的无向图G=(V,E),n=|V|,m=|E|,由V中全部n个定点和E中n-1条边构成的无向连通子图被称为G的一颗生成树. 边的权值之和 ...

  3. 洛谷P3366【模板】最小生成树-克鲁斯卡尔Kruskal算法详解附赠习题

    链接 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M&l ...

  4. 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

    推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...

  5. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  6. 洛谷 P2820 局域网

    题目链接 https://www.luogu.org/problemnew/show/P2820 题目背景 某个局域网内有n(n<=100)台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内 ...

  7. 洛谷——P2820 局域网

    P2820 局域网 题目背景 某个局域网内有n(n<=100)台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成 ...

  8. 模板<最小生成树>

    转载 最小生成树浅谈 这里介绍最小生成树的两种方法:Prim和Kruskal. 两者区别:Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣.Prim是以更新过的节点的连边找最小值,K ...

  9. POJ 2485 Highways【最小生成树最大权——简单模板】

    链接: http://poj.org/problem?id=2485 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22010#probl ...

随机推荐

  1. day63-webservice 03.解析cxf提供的例子

    Path配置: C:\Program Files (x86)\ScanSign;E:\app\zhongzh\product\11.2.0\dbhome_1\bin;D:\app\zhongzh\pr ...

  2. string基本字符系列容器(一)

    C++STL提供了string基本字符系列容器来处理字符串,可以把string理解成字符串类,它提供了添加,删除,替换,查找和比较等丰富的方法. 使用string容器,需要头文件包含声明#includ ...

  3. 项目二:品优购 第二天 AngularJS使用 brand商品页面的增删改查

    品优购电商系统开发 第2章 品牌管理 传智播客.黑马程序员 1.前端框架AngularJS入门 1.1 AngularJS简介 AngularJS  诞生于2009年,由Misko Hevery 等人 ...

  4. Web服务器父与子 Apache和Tomcat区别(转)

    From http://developer.51cto.com/art/201007/210894.htm 熟悉三国的朋友都知道曹操,曹操有二十五个儿子,其中最得曹操宠爱的是曹丕.曹植.曹彰三个,曹丕 ...

  5. Luogu 1099 树网的核

    bzoj1999 数据加强版(n <= 5e5) 较早的noip题,值得研究 重要结论:直径的最长性,任何从直径中离开直径的点到它离开的点的距离,都不会比直径的另一端到它离开的点长(否则就有新的 ...

  6. SVN常见问题及解决方式(一)

    1.每天早上上班要update SVN,每天下班要commit SVN.2.查看是谁动了我的代码,右键 tortoise 后查看 log 日志.3.文件被别人删除,在空白处右击,show log,可以 ...

  7. 编写高质量代码改善C#程序的157个建议——建议57:实现ISerializable的子类型应负责父类的序列化

    建议57:实现ISerializable的子类型应负责父类的序列化 我们将要实现的继承自ISerializable的类型Employee有一个父类Person,假设Person没有实现序列化,而现在子 ...

  8. CSS概念 - 可视化格式模型(二) 定位概述(普通流、绝对定位)

    2.定位概念 上一节熟悉了盒模型, 现在来看一下可视化格式模型和定位模型. 理解这两个模型的细微差异是非常重要的, 因为它们一起控制着如何在页面上布置每个元素 2.1 可视化格式模型 CSS有三种基本 ...

  9. 用JS实现表格的高亮显示

    1.所用事件详解 2.<thead>,<tbody>标签介绍 <thead> 标签定义表格的表头.该标签用于组合 HTML 表格的表头内容. thead 元素应该与 ...

  10. Java并发编程的3个特性

    一.原子性 原子行:即一个或者多个操作作为一个整体,要么全部执行,要么都不执行,并且操作在执行过程中不会被线程调度机制打断:而且这种操作一旦开始,就一直运行到结束,中间不会有任何上下文切换(conte ...