【BZOJ 3754】: Tree之最小方差树

题目链接:

  TP

题解:

  都是骗子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 }

 

没有什么不可能。
posted @ 2017-11-06 11:49  Troywar  阅读(254)  评论(0编辑  收藏  举报