【枚举】【最小生成树】【kruscal】bzoj3754 Tree之最小方差树

发现,若使方差最小,则使Σ(wi-平均数)最小即可。

因为权值的范围很小,所以我们可以枚举这个平均数,每次把边权赋成(wi-平均数)2,做kruscal。

但是,我们怎么知道枚举出来的平均数是不是恰好是我们的这n-1条边的呢? 就在更新答案的时候加个特判就行了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstring>
 5 using namespace std;
 6 #define N 101
 7 #define M 2001
 8 typedef double db;
 9 int fa[N],a[M],n,m,minv,maxv,rank[N];
10 db ans=999999999999999999999999999999.0;
11 bool cmp(const int &a,const int &b){return a>b;}
12 struct Edge{int u,v,w;db fw;void Read(){scanf("%d%d%d",&u,&v,&w);}}edges[M];
13 bool operator < (const Edge &a,const Edge &b){return a.fw<b.fw;}
14 void init()
15 {
16     for(int i=1;i<=n;i++) fa[i]=i;
17     memset(rank,0,sizeof(rank));
18 }
19 int findroot(int x)
20 {
21     if(x==fa[x]) return x;
22     int rt=findroot(fa[x]);
23     fa[x]=rt;
24     return rt;
25 }
26 void Union(const int &U,const int &V)
27 {
28     if(rank[U]<rank[V]) fa[U]=V;
29     else
30       {
31           fa[V]=U;
32           if(rank[U]==rank[V]) ++rank[U];
33       }
34 }
35 double sqr(const double &x){return x*x;}
36 void kruscal(const int &sum)
37 {
38     init(); db BA=(db)sum/(db)(n-1);
39     int tot=0,all=0; db f_all=0;
40     for(int i=1;i<=m;++i) edges[i].fw=sqr((db)edges[i].w-BA);
41     sort(edges+1,edges+m+1);
42     for(int i=1;i<=m;++i)
43       {
44           int f1=findroot(edges[i].u),f2=findroot(edges[i].v);
45           if(f1!=f2)
46             {
47                 Union(f1,f2);
48                 all+=edges[i].w;
49                 f_all+=edges[i].fw;
50                 if((++tot)==n-1) break;
51             }
52       }
53     if(all==sum) ans=min(ans,f_all);
54 }
55 int main()
56 {
57     scanf("%d%d",&n,&m);
58     for(int i=1;i<=m;++i) {edges[i].Read(); a[i]=edges[i].w;}
59     sort(a+1,a+m+1); for(int i=1;i<n;++i) minv+=a[i];
60     sort(a+1,a+m+1,cmp); for(int i=1;i<n;++i) maxv+=a[i];
61     for(int i=minv;i<=maxv;++i) kruscal(i);
62     printf("%.4f\n",sqrt(ans/(db)(n-1)));
63     return 0;
64 }
时间: 2024-10-12 20:04:45

【枚举】【最小生成树】【kruscal】bzoj3754 Tree之最小方差树的相关文章

BZOJ3754 Tree之最小方差树

Orz AutSky_JadeK他已经讲的很详细了,我只是个酱油233 (p.s. 这输出样例是错的...对的应该是0.7071貌似= =) 1 /************************************************************** 2 Problem: 3754 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:9024 ms 7 Memory:892 kb 8 **************

【BZOJ3754】Tree之最小方差树

Description Wayne在玩儿一个很有趣的游戏.在游戏中,Wayne建造了N个城市,现在他想在这些城市间修一些公路,当然并不是任意两个城市间都能修,为了道路系统的美观,一共只有M对城市间能修公路,即有若干三元组 (Ui,Vi,Ci)表示Ui和Vi间有一条长度为Ci的双向道路.当然,游戏保证了,若所有道路都修建,那么任意两城市可以互相到达.Wayne拥有恰好N-1支修建队,每支队伍能且仅能修一条道路.当然,修建长度越大,修建的劳累度也越高,游戏设定是修建长度为C的公路就会有C的劳累度.当

BZOJ 3754 Tree之最小方差树 MST

题目大意:求一个图的最小标准差生成树. 思路:毫无思路,之后看了题解.居然是一个很厉害的暴力. 一个很关键的地方:枚举平均值,然后根据(a - ave(a))^2将边排序,做最小生成树.所有的标准差最小值就是答案. 但是这是为什么?如果当前枚举的ave(a)并不是选取的边的平均值怎么办? 那么就一定有一个你会枚举到的ave(a)计算之后的标准差要比现在小. 这样基本就可以说明这个做法的正确性了.但是需要枚举的范围很大,虽然c只有100,但是按照多大枚举呢.很显然是按照EPS = 1.0 / (m

BZOJ 3754 Tree之最小方差树

枚举平均数. mdzz编译器. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxv 100500 #define maxe 200500 using namespace std; int n,m,l=0,r=0,father[maxv],rank[maxv]; double ans=999999

hdu 2489 Minimal Ratio Tree(dfs枚举 + 最小生成树)~~~

题目: 链接:点击打开链接 题意: 输入n个点,要求选m个点满足连接m个点的m-1条边权值和sum与点的权值和ans使得sum/ans最小,并输出所选的m个点,如果有多种情况就选第一个点最小的,如果第一个点也相同就选第二个点最小的........ 思路: 求一个图中的一颗子树,使得Sum(edge weight)/Sum(point weight)最小~ 数据量小,暴力枚举~~~~~dfs暴力枚举C(M,N)种情况. 枚举出这M个点之后,Sum(point weight)固定,进行prim或者K

hdu 2489 Minimal Ratio Tree 枚举+最小生成树

点的总数很小,直接枚举就好. #include <stdio.h> #include <string.h> #define N 20 #define inf 1000000 int mk[N],n,k,ans[N]; double low[N],val[N]; double map[N][N],MIN; double prim() { int i,j; double sum=0; double tot=0; for(i=1;i<=n;i++) low[i]=inf; int

蓝桥杯——算法提高 最小方差生成树

一.思路 枚举所有生成树的边权和值,对每一个枚举的边权和值sum,修改所有边的边权为(es[i].cost - sum * 1.0 / (N - 1))2,即方差公式的分子,然后跑最小生成树算法,同时记录边的原来的权值和,如果求出的“最小方差”生成树的边权值和为sum,那么,用这个"最小方差"去更新答案. 二.复杂度分析 时间复杂度:O(N * W * M * logM).N * W为枚举边权和值的时间.边权和值最小为0,最大为(N - 1) * W. 三.PS 这题据说蓝桥杯官网数据

算法笔记_164:算法提高 最小方差生成树(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 给定带权无向图,求出一颗方差最小的生成树. 输入格式 输入多组测试数据.第一行为N,M,依次是点数和边数.接下来M行,每行三个整数U,V,W,代表连接U,V的边,和权值W.保证图连通.n=m=0标志着测试文件的结束. 输出格式 对于每组数据,输出最小方差,四舍五入到0.01.输出格式按照样例. 样例输入 4 51 2 12 3 23 4 24 1 12 4 34 61 2 12 3 23 4 34 1 12 4 31 3 30 0 样

【算法】关于图论中的最小生成树(Minimum Spanning Tree)详解

喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 本节纲要 什么是图(network) 什么是最小生成树 (minimum spanning tree) 最小生成树的算法 什么是图(network)? 这里的图当然不是我们日常说的图片或者地图.通常情况下,我们把图看成是一种由"顶点"和"边"组成的抽象网络.在各个"顶点"间可以由"边"连接起来,使两个顶点间相互关联起来.图的结构可以描述多种复杂的数据对象,