原题网址:http://www.lydsy.com/JudgeOnline/problem.php?id=3754
思路有点像分数规划,分数规划是二分答案,根据答案每一个选项之间就有了优劣之分。一般的MST要每次取边权最小的,但是这一题要方差最小,那么边与边之间就没有直接的优劣之分,那么我们枚举平均数,对于每条边,我们算出
(ai−a¯)2
,那么我们只要最小化这个和就行了,就划归为一个普通的最小生成树问题。枚举平均数如果要枚举到精度是完全没有必要的,因为考虑两条边要分出优劣,假设这两条边权值是
a
和
#include<bits/stdc++.h>
const int N = 105;
const int M = 2050;
int n,m,fa[N];
struct rec{int u,v,c;double x;} a[M];
bool cmp(const rec &a, const rec &b){
return a.x < b.x;
}
double sqr(double x){
return x * x;
}
int find(int x){
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1; i<=m; i++)
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].c);
int ans = 1e9;
for (double ave=0; ave<=100; ave+=0.25){
for (int i=1; i<=m; i++) a[i].x = sqr(a[i].c - ave);
std::sort(a+1,a+m+1,cmp);
for (int i=1; i<=n; i++) fa[i] = i;
int sum = 0, sum2 = 0;
for (int i=1; i<=m; i++){
int f1 = find(a[i].u);
int f2 = find(a[i].v);
if (f1 == f2) continue;
fa[f1] = f2;
sum += a[i].c;
sum2 += a[i].c * a[i].c;
}
ans = std::min(ans,(n-1)*sum2-sum*sum);
}
printf("%.4f\n",sqrt(ans)/(n-1));
return 0;
}