[SMOJ1426]最小生成树
来源:互联网 发布:奥拉星淘宝怎么买号 编辑:程序博客网 时间:2024/06/16 07:03
题目描述
某个宇宙帝国有
n 个星球,由于宇宙的空间是三维的,因此每个星球的位置可以用三维坐标来表示(x,y,z) 。 任意两个不同的星球i 和j 都有一条边相连,边的距离是这样计算的:disij=min(|xi-xj|,|yi-yj|,|zi-zj|) 。 其中| |符号表示取绝对值。现在让你来挑n−1 条边,让这n 个星球连通成一个最小生成树,输出构成最小生成树的n−1 条边的长度总和。
输入格式 1426.in
第一行,一个整数
n 。1≤n≤100000
接下来有n 行,每行三个整数:x ,y ,z 。表示一个星球的坐标,−1000000000≤x,y,z≤1000000000 。 没有两个星球的位置完全重叠。
输出格式 1426.out
一行,构成最小生成树的
n−1 条边的长度总和。
输入样例 1426.in
5
11 -15 -15
14 -5 -15
-1 -1 -5
10 -4 -1
19 -4 19
输出样例 1426.out
4
首先回忆一下最小生成树问题的 Kruskal 算法:按耗费递增的顺序来考虑每条边,每次考虑一条边。当考虑某条边时,若将其加入到已选边的集合中会出现环路,则将其抛弃,否则,将它选入。
在本题中,如果直接枚举每两个星球之间的距离,再做一遍 Kruskal ,很显然是会 TLE 的。我们可以这样想:对于两条边
容易作个简单的推论:以
又或者,直接回到从贪心算法的角度来说,我们的目标是让所有星球连通,且总费用最小。那么只要考虑如何选取边才能使费用最小。显然,最终目的是要让全部边连通,那么我们与其选择用差值更大的情况,不如用按某个值排序后相邻的边,这样的选取原则不会存在更优的方案。
综上所述,只需要分别按各星球的
时间主要花费在排序上,总的时间复杂度为
参考代码:
#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;const int maxn = 1e5 + 100;struct Tplanet { int x, y, z; int id;} planet[maxn];struct Edge { int u, v, w; Edge () : u(0), v(0), w(0) {} Edge (int x, int y, int z) : u(x), v(y), w(z) {} bool operator < (const Edge x) const { return w < x.w; }} edge[maxn * 3];int n;int fa[maxn];bool byX(Tplanet i, Tplanet j) { return i.x < j.x; }bool byY(Tplanet i, Tplanet j) { return i.y < j.y; }bool byZ(Tplanet i, Tplanet j) { return i.z < j.z; }int find(int root) { return fa[root] == root ? root : fa[root] = find(fa[root]); }int main(void) { freopen("1426.in", "r", stdin); freopen("1426.out", "w", stdout); scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d%d%d", &planet[i].x, &planet[i].y, &planet[i].z); planet[i].id = i; fa[i] = i; } int cnt = 0; sort(planet, planet + n, byX); for (int i = 1; i < n; i++) edge[cnt++] = Edge(planet[i - 1].id, planet[i].id, planet[i].x - planet[i - 1].x); sort(planet, planet + n, byY); for (int i = 1; i < n; i++) edge[cnt++] = Edge(planet[i - 1].id, planet[i].id, planet[i].y - planet[i - 1].y); sort(planet, planet + n, byZ); for (int i = 1; i < n; i++) edge[cnt++] = Edge(planet[i - 1].id, planet[i].id, planet[i].z - planet[i - 1].z); sort(edge, edge + cnt); long long ans = 0; for (int i = 0; i < cnt; i++) { int fa_u = find(edge[i].u), fa_v = find(edge[i].v); if (fa_u != fa_v) { fa[fa_u] = fa_v; ans += edge[i].w; } } printf("%lld\n", ans); return 0;}
- [SMOJ1426]最小生成树
- 最小比例 最小生成树
- 最小生成树&&次最小生成树
- 最小生成生成树计数
- 树+最小生成树
- 最小生成树
- 最小生成树 MST
- 最小生成树Kruskal
- kruskal 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树 MST
- 最小生成树问题
- 最小生成树
- 最小生成树
- 最小生成树
- 第二天总结
- CSS常见兼容性问题总结
- 聚簇索引和非聚簇索引
- Redis的String数据类型
- leetcode 138. Copy List with Random Pointer
- [SMOJ1426]最小生成树
- 42.和为S的两个数字
- Linux命令(2)
- java设计模式(2/23)-多例模式(Multiton Pattern)
- 如何给自己的网站的评论功能
- Android调用系统相册或拍照实现头像更换
- JAVA多线程总结
- 转方阵
- 设置输出小数的位数