正题
题目大意
在一张图中选择一颗生成树使得边权的方差最小。
解题思路
我们很容易想到一种贪心,那就是在按照边权排好序后选择一段连续的区间然后使用这段区间构成最小生成树,这样时间复杂度是O(m3logm)O(m^3\log m)O(m3logm),时间复杂度难以接受。
那我们可以考虑枚举一个数xxx(精度在0.10.10.1内即可),然后将边权按照∣w−x∣|w-x|∣w−x∣排序,然后优先选取。每次枚举取最小值。
时间复杂度O(1000∗mlogm)O(1000*m\log m)O(1000∗mlogm),可以通过本题。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2110;
struct node{int x,y;double w,c;bool ok;
}a[N];
int n,m,fa[N];
double ans;
bool cMp(node x,node y)
{return x.w<y.w;}
int find(int x)
{return fa[x]==x?x:fa[x]=find(fa[x]);}
double check(double k)
{for(int i=1;i<=n;i++)fa[i]=i;for(int i=1;i<=m;i++)a[i].w=fabs(a[i].c-k),a[i].ok=0;sort(a+1,a+1+m,cMp);double ave=0,ans=0;for(int i=1;i<=m;i++)if(find(a[i].x)!=find(a[i].y))fa[fa[a[i].x]]=fa[a[i].y],ave+=a[i].c,a[i].ok=1;ave/=1.0*(n-1);for(int i=1;i<=m;i++)if(a[i].ok) ans+=(a[i].c-ave)*(a[i].c-ave);return sqrt(ans/(1.0*(n-1)));
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;i++)scanf("%d%d%lf",&a[i].x,&a[i].y,&a[i].c);ans=2147483647;for(double i=0;i<=100;i+=0.1)ans=min(ans,check(i));printf("%.4lf",ans);
}