bzoj3754 Tree之最小方差树 最小生成树+推性质
题目传送门
https://lydsy.com/JudgeOnline/problem.php?id=3754
题解
感觉这个思路挺神仙的。
后悔没有好好观察题目的数据范围,一直把 \(n\) 和 \(m\) 当成 1e5 来思考,\(c\) 竟然也只有 \(100\)。
有了数据范围以后可以发现,边权和位于 \(nc\) 级别,大概就是 \(10000\) 左右。
所以我们可以考虑枚举边权和,从而得到边权的平均数。
然后我们给每一条边的边权赋值为 \((\)原始边权 \(-\) 平均数\()^2\)。这样求出最小生成树。
但是有一个问题就是我们求出来的最小生成树的边权和不一定就是我们枚举的边权和。
不过很容易发现如果边权和不是我们枚举的边权和,那么我们在实际的边权和的地方计算出来的结果一定比这个优。所以没有影响。
上面的结论证明的话,大概就是考虑实际边权和为 \(s\),实际平方和为 \(t\)。我们枚举的平均数为 \(v\)。
Sum &= \sum (a_i - v) ^ 2\\
&= \sum a_i^2 - 2a_iv + nv^2\\
&= t - 2sv + nv^2
\end{align*}
\]
显然当 \(v = \frac sn\) 的时候最优,也就是 \(v\) 就是平均数的时候最优。
时间复杂度 \(O(ncm\log m)\)。
我跑的好慢啊。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 100 + 7;
const int M = 1000 + 7;
int n, m;
int fa[N];
struct Edges { int x, y, z; double w; } e[M];
inline bool operator < (const Edges &a, const Edges &b) { return a.w < b.w; }
inline bool operator > (const Edges &a, const Edges &b) { return a.w > b.w; }
inline int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
inline double kruskal(bool flag = 0) {
if (!flag) std::sort(e + 1, e + m + 1);
else std::sort(e + 1, e + m + 1, std::greater<Edges>());
for (int i = 1; i <= n; ++i) fa[i] = i;
double ans = 0;
for (int i = 1; i <= m; ++i) {
int x = find(e[i].x), y = find(e[i].y);
if (x == y) continue;
fa[y] = x, ans += e[i].w;
}
return ans;
}
inline void work() {
int l = kruskal(), r = kruskal(1);
double ans = 1e10;
for (int i = l; i <= r; ++i) {
double v = (double)i / (n - 1);
for (int j = 1; j <= m; ++j) e[j].w = (e[j].z - v) * (e[j].z - v);
smin(ans, kruskal());
}
printf("%.4lf\n", sqrt(ans / (n - 1)));
}
inline void init() {
read(n), read(m);
for (int i = 1; i <= m; ++i) read(e[i].x), read(e[i].y), read(e[i].z), e[i].w = e[i].z;
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
bzoj3754 Tree之最小方差树 最小生成树+推性质的更多相关文章
- [BZOJ3080]Minimum Variance Spanning Tree/[BZOJ3754]Tree之最小方差树
[BZOJ3080]Minimum Variance Spanning Tree/[BZOJ3754]Tree之最小方差树 题目大意: 给定一个\(n(n\le50)\)个点,\(m(m\le1000 ...
- [BZOJ3754]Tree之最小方差树
3754: Tree之最小方差树 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 402 Solved: 152[Submit][Status][Di ...
- 【bzoj3754】Tree之最小方差树 最小生成树
题目描述 给出一张无向图,求它的一棵生成树,使得选出的所有边的方差最小.输出这个最小方差. 输入 第一行两个正整数N,M 接下来M行,每行三个正整数Ui,Vi,Ci N<=100,M<=2 ...
- 【枚举】【最小生成树】【kruscal】bzoj3754 Tree之最小方差树
发现,若使方差最小,则使Σ(wi-平均数)2最小即可. 因为权值的范围很小,所以我们可以枚举这个平均数,每次把边权赋成(wi-平均数)2,做kruscal. 但是,我们怎么知道枚举出来的平均数是不是恰 ...
- bzoj 3754: Tree之最小方差树 模拟退火+随机三分
题目大意: 求最小方差生成树.N<=100,M<=2000,Ci<=100 题解: 首先我们知道这么一个东西: 一些数和另一个数的差的平方之和的最小值在这个数是这些数的平均值时取得 ...
- 【BZOJ 3754】: Tree之最小方差树
题目链接: TP 题解: 都是骗子233,我还以为是什么神奇的算法. 由于边权的范围很小,最小生成树和最大生成树之间的总和差不会太大,所以可以枚举边权和,再直接根据方差建最小生成树,每次更新答案即可. ...
- BZOJ 3754 Tree之最小方差树 MST
Description Wayne 在玩儿一个很有趣的游戏.在游戏中,Wayne 建造了N 个城市,现在他想在这些城市间修一些公路,当然并不是任意两个城市间都能修,为了道路系统的美观,一共只有M 对城 ...
- 【BZOJ 3754】Tree之最小方差树
http://www.lydsy.com/JudgeOnline/problem.php?id=3754 核心思想:暴力枚举所有可能的平均数,对每个平均数排序后Kruskal. 正确的答案一定是最小的 ...
- BZOJ 3754 Tree之最小方差树
枚举平均数. mdzz编译器. #include<iostream> #include<cstdio> #include<cstring> #include< ...
随机推荐
- SpringMvc中@ModelAttribute的运用
/** * 1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用! * 2. @ModelAttribute 注解也可以来修饰目标方法 POJO ...
- A 内存挂 B 封包挂 C 钩子挂 D CALL挂 外挂
https://www.zhihu.com/question/32291769 作者:猎狐链接:https://www.zhihu.com/question/32291769/answer/70929 ...
- 【Linux 应用编程】基础知识
错误提示 Linux 提供的系统调用API,通常会在失败的时候返回 -1.如果想获取更多更详细的报错信息,需要借助全局变量 errno 和 perror 函数: #include <stdio. ...
- IP子网的划分
一.划分子网的具体步骤 已知192.168.1.0/24,划分8个子网(一个ip划分8个子网,即网络位不再是24位)1100 0000.1010 1000.0000 0001.0000 00001 . ...
- 红帽学习笔记[RHCSA] 第二课[文件、目录、相关命令]
第二课 常用的目录结构与用途 / 根目录 /boot 存储的是系统起动时的信息和内核等 /dev 存储的是设备文件 /etc 存储的是系统的配置文件 /root 存储的是root用户的家目录 /hom ...
- 实验3&总结5
老师:lijin2019,助教:晨晨果 提交作业 实验三 String类的应用 实验目的 掌握类String类的使用: 学会使用JDK帮助文档: 实验内容 1.已知字符串:"this is ...
- Nginx 的方向代理及配置
最近有打算研读nginx源代码,看到网上介绍nginx可以作为一个反向代理服务器完成负载均衡.所以搜罗了一些关于反向代理服务器的内容,整理综合. 一 概述 反向代理(Reverse Proxy)方式 ...
- SELECT 与 SET给标量赋值
本文转自 :https://blog.csdn.net/perddy/article/details/4033406 SQL Server推荐使用 SET 而不是 SELECT 对变量进行赋值.当表达 ...
- SpringMVC框架 课程笔记
SpringMVC框架 课程笔记 第0章 SpringMVC框架的核心内容 1.SpringMVC 概述 2.SpringMVC 的 HelloWorld 3.使用 @RequestMapping 映 ...
- 2019 CSP-S初赛游记
2019-10-19 ——这个注定要被载入史册的日子 作为一名初中生,和lpy大佬一同参加提高组的比赛,而今年普及组和提高组的时间竟然不一样,于是——凌晨六点半,来到了pdyz和高中生一起坐车去. 高 ...