Solution

我们考虑答案的表达式:

\[ans = \sqrt{\frac{\sum_{i = 1}^{n - 1} (w_i - \overline{w})^2}{n - 1}}
\]

其中\(w[i]\)表示选择的每一条边的权值.

考虑一种朴素的做法:

我们枚举每一个\(\overline{w}\), 把所有边按照其对答案的贡献\((w_i - \overline{w})^2\)排序, 然后用普通的kruskal解决即可.

这种做法的本质在于枚举每一个可能的\((w_i - \overline{w})\)序列. 我们注意到, \((w_i - \overline w)\)是一个二次函数, 因此我们当\(\overline w\)上升时, 该值先下降再上升.

考虑什么时候两条边对应的贡献在排好序的序列中会交换位置: \((w_i - \overline w)^2 = (w_j - \overline w)^2\), 即\(\overline w = \frac {w_i + w_j} 2\)

两条边的贡献在序列中最多只会交换一次位置, 因此我们只需要枚举每个临界值, 就相当于枚举所有合法的序列. 跑kruskal即可.

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector> using namespace std;
const double INF = 1e50, EPS = 1e-9;
const int N = 20;
int n;
int x[N], y[N];
double w[N * N], dis[N][N];
struct edge
{
int u, v;
double w;
inline edge() {}
inline edge(int _u, int _v, double _w) { u = _u; v = _v; w = _w; }
inline int operator <(const edge &a) const { return w < a.w; }
}edg[N * N];
inline double sqr(double a) { return a * a; }
inline double getDistance(int u, int v) { return sqrt(sqr(x[u] - x[v]) + sqr(y[u] - y[v])); }
struct disjointSet
{
int pre[N];
inline void clear() { for (int i = 0; i < n; ++ i) pre[i] = i; }
inline int access(int u)
{
if (pre[u] == u) return u;
return pre[u] = access(pre[u]);
}
}st;
inline double work(double avr)
{
int tot = 0;
for (int i = 0; i < n; ++ i) for (int j = i + 1; j < n; ++ j) edg[tot ++] = edge(i, j, sqr(dis[i][j] - avr));
sort(edg, edg + tot);
st.clear();
vector<int> bck; bck.clear(); int cnt = 0;
for (int i = 0; cnt < n - 1; ++ i)
{
int u = edg[i].u, v = edg[i].v, rootOfU = st.access(u), rootOfV = st.access(v);
if (rootOfU == rootOfV) continue;
++ cnt;
st.pre[rootOfU] = rootOfV; bck.push_back(i);
}
double sum = 0, res = 0;
for (int i = 0; i < n - 1; ++ i) sum += dis[edg[bck[i]].u][edg[bck[i]].v];
for (int i = 0; i < n - 1; ++ i) res += sqr(dis[edg[bck[i]].u][edg[bck[i]].v] - sum / (n - 1));
return sqrt(res / (n - 1));
}
int main()
{ #ifndef ONLINE_JUDGE freopen("mst.in", "r", stdin);
freopen("mst.out", "w", stdout); #endif int T; scanf("%d", &T);
for (int cs = 0; cs < T; ++ cs)
{
scanf("%d", &n);
for (int i = 0; i < n; ++ i) scanf("%d", x + i);
for (int i = 0; i < n; ++ i) scanf("%d", y + i);
int tot = 0;
for (int i = 0; i < n; ++ i) for (int j = i + 1; j < n; ++ j) dis[i][j] = w[tot ++] = getDistance(i, j);
sort(w, w + tot);
double ans = INF;
for (int i = 0; i < tot; ++ i) for(int j = i + 1; j < tot; ++ j)
ans = min(ans, work((w[i] + w[j]) / 2 + EPS)), ans = min(ans, work((w[i] + w[j]) / 2 - EPS));
printf("%.3lf\n", ans);
}
}

NOI模拟题4 Problem A: 生成树(mst)的更多相关文章

  1. NOI模拟题1 Problem A: sub

    题面 Sample Input 5 7 2 -1 -3 1 1 1 2 1 3 3 4 3 5 2 1 3 0 2 1 2 1 2 1 1 -3 2 Sample Output 2 4 5 2 HIN ...

  2. NOI模拟题6 Problem C: Circle

    Solution 首先这个矩阵, 很明显的就是Vandermonde矩阵. 我们有公式: \[ |F_n| = \prod_{1 \le j < i \le n} (a_i - a_j) \] ...

  3. NOI模拟题5 Problem A: 开场题

    Solution 注意到\(\gcd\)具有结合律: \[ \gcd(a, b, c) = \gcd(a, \gcd(b, c)) \] 因此我们从后往前, 对于每个位置\(L\), 找到每一段不同的 ...

  4. NOI模拟题4 Problem C: 填格子(board)

    Solution 首先我们要有敏锐的直觉: 我们将每一列中不选哪种颜色看作是一个序列, 则我们发现这个序列要求相邻两位的颜色不同. 我们还发现, 一个这样的序列对应两种不同的合法的棋盘, 因此统计合法 ...

  5. NOI模拟题4 Problem B: 小狐狸(fox)

    Solution 考虑分开统计朝向每一个方向的所有狐狸对答案的贡献. 比如说以向右为例, 我们用箭标表示每一只狐狸的方向, 用\('\)表示当前一步移动之前的每一只狐狸的位置. \[ \begin{a ...

  6. 花海漫步 NOI模拟题

    题目好像难以看懂? 题目大意 给出一个字符串\(S\),统计满足以下条件的\((i,j,p,q)\)的数量. \(i \leq j, p \leq q\) \(S[i..j],S[p..q]\)是回文 ...

  7. 神奇的矩阵 NOI模拟题

    神奇的矩阵 题目大意 有一个矩阵\(A\),第一行是给出的,接下来第\(x\)行,第\(y\)个元素的值为数字\(A_{x-1,y}\)在\(\{A_{x-1,1},A_{x-1,2},A_{x-1, ...

  8. Western Subregional of NEERC, Minsk, Wednesday, November 4, 2015 Problem K. UTF-8 Decoder 模拟题

    Problem K. UTF-8 Decoder 题目连接: http://opentrains.snarknews.info/~ejudge/team.cgi?SID=c75360ed7f2c702 ...

  9. 2010-2011 ACM-ICPC, NEERC, Moscow Subregional Contest Problem I. Interest Targeting 模拟题

    Problem I. Interest Targeting 题目连接: http://codeforces.com/gym/100714 Description A unique display ad ...

随机推荐

  1. easyui 判断密码是否输入一致

    1.首先要扩展validatebox,添加验证两次密码功能 $.extend($.fn.validatebox.defaults.rules, { eqPassword:{ validator:fun ...

  2. 关于html头部引用(meta,link)

    /*这一段头部表示 如果安装了GCF,则使用GCF来渲染页面,如果为安装GCF,则使用最高版本的IE内核进行渲染.*/<meta content="IE=edge,chrome=1&q ...

  3. Lucene.Net 精品教程

    http://www.cnblogs.com/piziyimao/archive/2013/01/31/2887072.html

  4. IOS开发---菜鸟学习之路--(十二)-利用ASIHTTPRequest进行异步获取数据

    想要实现异步获取的话我这边了解过来有两个非常简单的方式 一个是利用ASIHTTPRequest来实现异步获取数据 另一个则是利用MBProgressHUD来实现异步获取数据 本章就先来讲解如何利用AS ...

  5. IOS开发学习笔记042-UITableView总结2

    一.自定义非等高的cell         如常见的微博界面,有的微博只有文字,有的有文字和图片.这些微博的高度不固定需要重新计算. 这里简单说一下几种方法.前面的步骤和设置等高的cell一样.现在来 ...

  6. 想进BAT?这些面试题助你一臂之力

    1 软性热身题 这种题目,考的就是你的软性能力,比如表达能力,理解能力,协调能力,一个词概括就是套路.这类题目会在面试开始热身的时候,问一道两题,不会多,但是如果你能回答的有条不紊,清晰达意,那么就会 ...

  7. [python][django 1.10中文文档]

    https://docs.djangoproject.com/en/1.10/  官方文档,点我下载 推荐一个翻译django 1.8.2的网址: 推荐一个翻译django 1.10的博客:(着重推荐 ...

  8. bat 处理adb脚本

    @echo off REM Funtion: 测试parsermode 接口CdxParserGetMediaInfo 和CdxParserRead REM Code by lzp 2017-05-0 ...

  9. excel模板解析前后设计变化,以及我对此的看法和感受

    前言:近期也在做Excel模板的解析工作,目前来说,应该是第三版了.我最开始做的,就是垒鸡窝,虽然考虑了1.0提出的关于excel解析的一些建议和问题(单个模板),但是真的毫无设计可言.就几个工具类, ...

  10. Summary—【base】(HTML)

    Html知识点: 1. 建议开发人员计算机基本配置 a) 显示所有文件的后缀名* b) 文件的排列方式改为详细信息,并且名称一定要能够全部显示出来 c) 使用小的任务栏 d) 将常用的工具锁定到任务栏 ...