Bzoj3754 Tree之最小方差树 MST

原题网址:http://www.lydsy.com/JudgeOnline/problem.php?id=3754
思路有点像分数规划,分数规划是二分答案,根据答案每一个选项之间就有了优劣之分。一般的MST要每次取边权最小的,但是这一题要方差最小,那么边与边之间就没有直接的优劣之分,那么我们枚举平均数,对于每条边,我们算出 (aia¯)2 ,那么我们只要最小化这个和就行了,就划归为一个普通的最小生成树问题。枚举平均数如果要枚举到精度是完全没有必要的,因为考虑两条边要分出优劣,假设这两条边权值是 a b,那么它们的平均数是 a+b2 ,枚举的平均数在区间 [a,a+b2) 之内和 (a+b2,b] 之内是等效的,在这两个区间内只要各取一个点尝试即可,又因为边权都是整数,那么每次 +0.25 就可以枚举到所有必要的决策点。

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值