[bzoj3754][GDOI2014模拟]Tree

来源:互联网 发布:java跳跃表 编辑:程序博客网 时间:2024/06/05 02:18

Description

最小标准差生成树。。。。
n<=100,m<=2000,边权<=100

Solution

其实我比赛时想的是可以的,不过不用二分,而用枚举。
没错,枚举平均数。
不过,可能的数太多了,得另想办法。
我们把排好序的数按顺序排列,对于相邻的两个数a和b,和他们的平均数ave,区间[a,ave]中的任意一个数为平均数所形成的最小生成树都是一样的。
同理[ave,b]。
所以我们可以以0.25为间隔来枚举,这样就可以了.

Code

#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define sqr(x) (x)*(x)#define N 105#define M 2005using namespace std;typedef double db;const db eps=0.25;struct note{int x,y,z;}a[M];db ave,cnt,ans,all;int n,m,tot,up,f[N];bool bz[M];bool cmp(note x,note y) {return sqr(x.z-ave)<sqr(y.z-ave);}int get(int x) {return f[x]?f[x]=get(f[x]):x;}int main() {    scanf("%d%d",&n,&m);ans=0x7fffffff;    fo(i,1,m) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),    up=max(up,a[i].z);    for(;ave<=up;ave+=eps) {        sort(a+1,a+m+1,cmp);memset(f,0,sizeof(f));        memset(bz,0,sizeof(bz));tot=all=0;        fo(i,1,m) {            int x=get(a[i].x),y=get(a[i].y);            if (x!=y) tot++,all+=a[i].z,bz[i]=1,f[y]=x;            if (tot==n-1) break;        }           all/=n-1;cnt=0;        fo(i,1,m) if (bz[i]) cnt+=sqr(a[i].z-all);        ans=min(ans,sqrt(cnt/(n-1)));    }    printf("%.4lf",ans);}
0 0