给定带权无向图,求出一颗方差最小的生成树。
_________________________________________________
方差就是各个数的平均值与各个数的差的平方的和的平均值。
sum((a_i-ave)^2)/n
多组数据。
枚举是不现实的。但是不枚举如何知道他们的平均值?
把所有的边排序,取出最小的n-1条和最大的n-1条分别求和,为mn和mx。那么ave*(n-1)一定在这个范围内。
枚举这个值(也就是n-1条边的和),除以n-1就得到了平均值,用图中所有的变用这个平均值求差值的平方作为变得新权ww。用ww求新的最小生成树。
开始,怀疑过:有些和是不会产生的,那么他们产生的方差会不会影响最终结果。
假设,和为s时产生了平均数ave,用它选了相应最小的n-1条树边并产生的对应的方差。但是,这个和s并不会产生,当然ave也就不会产生。
我们假设,对应的n-1条边真正产生的平均值是AVE,那么很明显AVE要比ave也好,当枚举到对应的值时自然会得到更好的解!
_________________________________________________
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=55; 4 const int maxm=1010; 5 struct edge 6 { 7 int u,v; 8 double w,ww; 9 }e[maxm]; 10 int n,m,mn,mx; 11 bool cmp(edge a,edge b) 12 { 13 return a.w<b.w; 14 } 15 bool cmp2(edge a,edge b) 16 { 17 return a.ww<b.ww; 18 } 19 double ans; 20 int cas; 21 int f[maxn]; 22 int find(int x) 23 { 24 return f[x]==x?x:f[x]=find(f[x]); 25 } 26 void join(int x,int y) 27 { 28 x=find(x);y=find(y); 29 if(rand()%2)f[x]=y; 30 else f[y]=x; 31 } 32 int main() 33 { 34 while(scanf("%d%d",&n,&m)==2 && n &&m) 35 { 36 cas++; 37 for(int i=1;i<=m;++i)scanf("%d%d%lf",&e[i].u,&e[i].v,&e[i].w); 38 sort(e+1,e+1+m,cmp); 39 mn=mx=0; 40 ans=100000000000; 41 for(int i=1;i<n;++i)mn+=e[i].w; 42 for(int i=m;i>m-n+1;--i)mx+=e[i].w; 43 for(int i=mn;i<=mx;++i) 44 { 45 double tp=0; 46 double pj=1.0*i/(n-1); 47 for(int j=1;j<=m;++j)e[j].ww=(e[j].w-pj)*(e[j].w-pj); 48 for(int j=1;j<=n;++j)f[j]=j; 49 sort(e+1,e+1+m,cmp2); 50 int js=0; 51 for(int j=1;j<=m;++j) 52 { 53 if(find(e[j].u)!=find(e[j].v)) 54 { 55 join(e[j].u,e[j].v); 56 js++; 57 tp+=e[j].ww; 58 if(js==n-1)break; 59 } 60 } 61 ans=min(ans,tp); 62 } 63 printf("Case %d: %.2lf\n",cas,ans/(n-1)); 64 } 65 return 0; 66 }View Code