Bzoj3754 Tree之最小方差樹 MST

原題網址:http://www.lydsy.com/JudgeOnline/problem.php?id=3754
思路有點像分數規劃,分數規劃是二分答案,根據答案每一個選項之間就有了優劣之分。一般的MST要每次取邊權最小的,但是這一題要方差最小,那麼邊與邊之間就沒有直接的優劣之分,那麼我們枚舉平均數,對於每條邊,我們算出(aia¯)2 ,那麼我們只要最小化這個和就行了,就劃歸爲一個普通的最小生成樹問題。枚舉平均數如果要枚舉到精度是完全沒有必要的,因爲考慮兩條邊要分出優劣,假設這兩條邊權值是ab ,那麼它們的平均數是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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章