zoukankan      html  css  js  c++  java
  • 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
    ",cas,ans/(n-1));
    64     }
    65     return 0;
    66 }
    View Code
  • 相关阅读:
    台州 OJ 3847 Mowing the Lawn 线性DP 单调队列
    洛谷 OJ P1417 烹调方案 01背包
    快速幂取模
    台州 OJ 2649 More is better 并查集
    UVa 1640
    UVa 11971
    UVa 10900
    UVa 11346
    UVa 10288
    UVa 1639
  • 原文地址:https://www.cnblogs.com/gryzy/p/14514027.html
Copyright © 2011-2022 走看看