[BZOJ3754]Tree之最小方差树
3754: Tree之最小方差树
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 402 Solved: 152
[Submit][Status][Discuss]
Description
Wayne在玩儿一个很有趣的游戏。在游戏中,Wayne建造了N个城市,现在他想在这些城市间修一些公路,当然并不是任意两个城市间都能修,为了道路系统的美观,一共只有M对城市间能修公路,即有若干三元组 (Ui,Vi,Ci)表示Ui和Vi间有一条长度为Ci的双向道路。当然,游戏保证了,若所有道路都修建,那么任意两城市可以互相到达。Wayne拥有恰好N-1支修建队,每支队伍能且仅能修一条道路。当然,修建长度越大,修建的劳累度也越高,游戏设定是修建长度为C的公路就会有C的劳累度。当所有的队伍完工后,整个城市群必须连通,而这些修建队伍们会看看其他队伍的劳累情况,若劳累情况差异过大,可能就会引发骚动,不利于社会和谐发展。Wayne对这个问题非常头疼,于是他想知道,这N1支队伍劳累度的标准差最小能有多少。
标准差的定为:设有N个数,分别为ai,它们的平均数为 ,那么标准差就是
Input
第一行两个正整数N,M
接下来M行,每行三个正整数Ui,Vi,Ci
Output
输出最小的标准差,保留四位小数。
Sample Input
3 3
1 2 1
2 3 2
3 1 3
1 2 1
2 3 2
3 1 3
Sample Output
0.5000
HINT
N<=100,M<=2000,Ci<=100
Source
此题要最小化$\sqrt{\frac{\sum\limits_{a_i\in S}(a_i-\bar a)^2}{n-1}}$等价于最小化$\sum\limits_{a_i\in S}(a_i-\bar a)^2$ 其中S中的所有边组成一个生成树
设$f(x)=\sum\limits_{a_i\in S}(a_i-x)^2$,则$f(x)=\sum\limits_{a_i \in S}(x^2-2*a_i*x+a_i^2)$其中当$x=\bar a$时取得最小值。
所以可以枚举平均值x,然后求最小生成树,求出来的边如果平均值不等于x。当枚举到他们的平均值时,答案一定比当前小,统计最小值即可。
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define N 105 6 #define M 2010 7 #define sqr(x) ((x)*(x)) 8 using namespace std; 9 int n,m,tot,f[N];double ans=1e9; 10 int find(int x){return f[x]==x?x:f[x]=find(f[x]);} 11 struct edge{int x,y,c;double w;}e[M]; 12 inline bool operator<(edge x,edge y){return x.w<y.w;} 13 double solve() 14 { 15 for(int i=1;i<=n;i++)f[i]=i; 16 int tot=0;double sum=0; 17 for(int i=1;tot!=n-1;i++) 18 { 19 int fx=find(e[i].x),fy=find(e[i].y); 20 if(fx==fy)continue; 21 tot++; 22 f[fx]=fy; 23 sum+=e[i].w; 24 } 25 return sum; 26 } 27 int main() 28 { 29 scanf("%d%d",&n,&m); 30 for(int i=1;i<=m;i++) 31 scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].c),e[i].w=e[i].c; 32 int Min,Max; 33 sort(e+1,e+m+1); 34 Min=solve(); 35 reverse(e+1,e+m+1); 36 Max=solve(); 37 for(int i=Min;i<=Max;i++) 38 { 39 double ave=i*1.0/(n-1); 40 for(int j=1;j<=m;j++) 41 e[j].w=sqr(e[j].c-ave); 42 sort(e+1,e+m+1); 43 ans=min(ans,solve()); 44 } 45 printf("%.4lf\n",sqrt(ans/(n-1))); 46 }
就让我永远不在这里写什么有意义的话--月下孤狼