noip.ac 3286
给定带权无向图,求出一颗方差最小的生成树。
_________________________________________________
方差就是各个数的平均值与各个数的差的平方的和的平均值。
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
赞 (0)