【BZOJ 3754】: Tree之最小方差树
题目链接:
题解:
都是骗子233,我还以为是什么神奇的算法。
由于边权的范围很小,最小生成树和最大生成树之间的总和差不会太大,所以可以枚举边权和,再直接根据方差建最小生成树,每次更新答案即可。
代码:
1 #define Troy 2 3 #include <bits/stdc++.h> 4 5 using namespace std; 6 7 inline int read(){ 8 int s=0,k=1;char ch=getchar(); 9 while(ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar(); 10 while(ch>47&ch<='9') s=s*10+(ch^48),ch=getchar(); 11 return s*k; 12 } 13 14 int n,m,fa[101],sum; 15 double ans; 16 17 inline int finds(int x){ 18 return x==fa[x]?x:fa[x]=finds(fa[x]); 19 } 20 21 struct node{ 22 int u,v,c; 23 double ave; 24 }edge[2010]; 25 26 inline bool cmp1(const node &x,const node &y){ 27 return x.c<y.c; 28 } 29 30 inline bool cmp2(const node &x,const node &y){ 31 return x.ave<y.ave; 32 } 33 34 inline void MST(){ 35 for(int i=1;i<=n;++i) fa[i]=i; 36 sum=0;double now=0.0; 37 for(int i=1,j=0;j^n-1;++i){ 38 int x=finds(edge[i].u),y=finds(edge[i].v); 39 if(x!=y){ 40 // printf("edge[%d].ave=%f\n",i,edge[i].ave); 41 ++j;fa[y]=x; 42 now+=edge[i].ave;sum+=edge[i].c; 43 } 44 } 45 ans=min(ans,now); 46 } 47 48 inline double sqr(double x){ 49 return x*x; 50 } 51 52 inline void make(int tot){ 53 for(int i=1;i<=m;++i) 54 edge[i].ave=sqr(edge[i].c-tot*1.0/(n-1)); 55 sort(edge+1,edge+1+m,cmp2); 56 } 57 58 int main(){ 59 n=read(),m=read(); 60 for(int i=1;i<=m;++i) { 61 int u=read(),v=read(),c=read(); 62 edge[i]=(node){u,v,c,0}; 63 } 64 sort(edge+1,edge+m+1,cmp1); 65 MST();int l=sum; 66 for(int i=1;(i<<1)<=m;++i)swap(edge[i],edge[m-i+1]); 67 MST();int r=sum; 68 ans=1e16; 69 // printf("l=%d r=%d\n",l,r); 70 for(int i=l;i<=r;++i){ 71 make(i); 72 MST(); 73 // puts(""); 74 } 75 printf("%.4f",sqrt(ans/(n-1))); 76 }
没有什么不可能。