BZOJ 3754 Tree之最小方差树 MST

题目大意:求一个图的最小标准差生成树。

思路:毫无思路,之后看了题解。居然是一个很厉害的暴力。

一个很关键的地方:枚举平均值,然后根据(a - ave(a))^2将边排序,做最小生成树。所有的标准差最小值就是答案。

但是这是为什么?如果当前枚举的ave(a)并不是选取的边的平均值怎么办?

那么就一定有一个你会枚举到的ave(a)计算之后的标准差要比现在小。

这样基本就可以说明这个做法的正确性了。但是需要枚举的范围很大,虽然c只有100,但是按照多大枚举呢。很显然是按照EPS = 1.0 / (m - 1)枚举,因为平均值一定在这其中产生。还有一个小剪枝就是将原图做一次最小生成树和最大生成树,确定枚举的上界和下界。

(为什么我的代码跑了10s+555~~~

CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define MAX 2010
#define INF 0x3f3f3f3f
#define EPS (1.0 / (points - 1))
using namespace std;

struct Edge{
	int x,y,len;
	double temp;

	bool operator <(const Edge &a)const {
		return len < a.len;
	}
	void Read() {
		scanf("%d%d%d",&x,&y,&len);
	}
}edge[MAX];

int points,edges;
int father[MAX];

int Find(int x)
{
	if(father[x] == x)	return x;
	return father[x] = Find(father[x]);
}

inline int MST()
{
	for(int i = 1; i <= points; ++i)
		father[i] = i;
	int re = 0;
	for(int i = 1; i <= edges; ++i) {
		int fx = Find(edge[i].x);
		int fy = Find(edge[i].y);
		if(fx != fy) {
			father[fx] = fy;
			re += edge[i].len;
		}
	}
	return re;
}

bool cmp(const Edge &a,const Edge &b)
{
	return a.temp < b.temp;
}

inline double Calc(double average)
{
	for(int i = 1; i <= points; ++i)
		father[i] = i;
	for(int i = 1; i <= edges; ++i)
		edge[i].temp = (average - edge[i].len) * (average - edge[i].len);
	sort(edge + 1,edge + edges + 1,cmp);
	double re = .0;
	for(int i = 1; i <= edges; ++i) {
		int fx = Find(edge[i].x);
		int fy = Find(edge[i].y);
		if(fx != fy) {
			father[fx] = fy;
			re += edge[i].temp;
		}
	}
	return sqrt(re / (points - 1));
}

int main()
{
	cin >> points >> edges;
	for(int i = 1; i <= edges; ++i)
		edge[i].Read();
	sort(edge + 1,edge + edges + 1);
	double range_min = (double)MST() / (points - 1);
	reverse(edge + 1,edge + edges + 1);
	double range_max = (double)MST() / (points - 1);
	double ans = INF;
	for(int i = 0; EPS * i + range_min <= range_max; ++i)
		ans = min(ans,Calc(EPS * i + range_min));
	cout << fixed << setprecision(4) << ans << endl;
	return 0;
}

时间: 2024-10-10 12:38:48

BZOJ 3754 Tree之最小方差树 MST的相关文章

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

【BZOJ3754】Tree之最小方差树

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

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

发现,若使方差最小,则使Σ(wi-平均数)最小即可. 因为权值的范围很小,所以我们可以枚举这个平均数,每次把边权赋成(wi-平均数)2,做kruscal. 但是,我们怎么知道枚举出来的平均数是不是恰好是我们的这n-1条边的呢? 就在更新答案的时候加个特判就行了. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 using namespace st

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 **************

【模板】最小割树(Gomory-Hu Tree)

传送门 Description 给定一个\(n\)个点\(m\)条边的无向连通图,多次询问两点之间的最小割 两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不连通 Solution 对于一张无向图,如果 \(s \rightarrow t\) 的最大流是 \(f\),\(s\), \(t\) 所在的割集为 \(S\), \(T\),那么 \(\forall_{x \in S, y \in T}\), \(\operatorname{maxflow}(x

【BZOJ-2229】最小割 最小割树(最大流+分治)

2229: [Zjoi2011]最小割 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1565  Solved: 560[Submit][Status][Discuss] Description 小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割. 对于带权图来说,将所有顶点处在不同部分的边的

BZOJ 1835 基站选址(线段树优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1835 题意:有N个村庄坐落在一条直线上,第 i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村 庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位 置,使得总费用最小. 思路: 另外,程序中的n=n+1,m=

[LeetCode] Minimum Height Trees 最小高度树

For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write

[ZJOI2011] 最小割 - 最小割树

最小割树裸题 建树后,以每个点为根跑DFS求出距离矩阵,然后暴力回答询问即可 #include <bits/stdc++.h> using namespace std; #define int long long const int maxn=6e2; const int maxm=4e4; const int inf=1e13; int n,m,q; //for the target graph vector <pair<int,int> > g[maxn]; voi