bzoj 3754: Tree之最小方差树 模拟退火+随机三分
题目大意:
求最小方差生成树.N<=100,M<=2000,Ci<=100
题解:
首先我们知道这么一个东西:
- 一些数和另一个数的差的平方之和的最小值在这个数是这些数的平均值时取得
所以我们可以枚举这个平均数,然后计算所有边与该值的差的平方
然后扔下去跑一个最小生成树
然后我们通过枚举这个平均数发现这个平均数和答案的对应函数的图像是一个波形函数
所以我们可以直接在这个波形图像上找函数最低点:
相应的就有
- 爬山算法
- 模拟退火
两种算法
所以我们可以先在全局用模拟退火然后在局部用爬山算法。
然而还是每三组数据就Wa一次
然后发现这样的话极限数据只需要0.8s,还有1.2s可以用
所以可以在全局再三分找函数最低点.
随机化左右端点然后再三分.
随机化22次端点极限数据可以跑到1.3s
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 128;
const int maxm = 2048;
const double eps = 1e-10;
const double det = 0.99;
struct Node{
int u,v,bed;
double d;
bool friend operator < (const Node &a,const Node &b){
return a.d < b.d;
}
}G[maxm];
int fa[maxn];
inline int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}
int n,m;
inline double work(double mid){
for(int i=1;i<=n;++i) fa[i] = i;
for(int i=1;i<=m;++i) G[i].d = (G[i].bed - mid)*(G[i].bed - mid);
sort(G+1,G+m+1);
int cnt = 0;double sum = 0;
for(int i=1;i<=m;++i){
int x = find(G[i].u);
int y = find(G[i].v);
if(x != y){
sum += G[i].d;
fa[x] = y;
if(++cnt == n-1) break;
}
}
return sqrt(sum/(n-1));
}
inline double ran(){
return (1.0*rand())/1000.0;
}
double ans = 1e10,ans_p;
inline double f(double mid){
double x = work(mid);
if(ans > x){
ans = x;
ans_p = mid;
}return x;
}
int main(){
srand(2333);
read(n);read(m);
int minn = 0x7f7f7f7f,maxx = -0x7f7f7f7f;
for(int i=1;i<=m;++i){
read(G[i].u);
read(G[i].v);
read(G[i].bed);
minn = min(minn,G[i].bed);
maxx = max(maxx,G[i].bed);
}
double l = minn,r = maxx,nx,t,val_nx;
double T = 50.0,nw = (l+r)/2,val_nw;
while(T > eps){
nx = ( rand() % 2 == 0 ? -1 : 1)*ran()*T;
t = val_nw - (val_nx = f(nx));
if(t > 0 || exp(t/T) >= ran() ){
nw = nx;
val_nw = val_nx;
}
T *= det;
}
while(r-l > eps){
double midx = (l+l+r)/3;
double midy = (l+r+r)/3;
double x = f(midx);
double y = f(midy);
if(x < y) r = midy;
else l = midx;
}
ans = min(ans,f(l));
int num = 22;
while(num--){
double l = minn + rand()*ran()*0.1;
double r = maxx - rand()*ran()*0.1;
if(l > r) swap(l,r);
while(r-l > eps){
double midx = (l+l+r)/3;
double midy = (l+r+r)/3;
double x = f(midx);
double y = f(midy);
if(x < y) r = midy;
else l = midx;
}ans = min(ans,f(l));
}
printf("%.4lf\n",ans);
getchar();getchar();
return 0;
}
bzoj 3754: Tree之最小方差树 模拟退火+随机三分的更多相关文章
- BZOJ 3754 Tree之最小方差树 MST
Description Wayne 在玩儿一个很有趣的游戏.在游戏中,Wayne 建造了N 个城市,现在他想在这些城市间修一些公路,当然并不是任意两个城市间都能修,为了道路系统的美观,一共只有M 对城 ...
- BZOJ 3754 Tree之最小方差树
枚举平均数. mdzz编译器. #include<iostream> #include<cstdio> #include<cstring> #include< ...
- [BZOJ3754]Tree之最小方差树
3754: Tree之最小方差树 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 402 Solved: 152[Submit][Status][Di ...
- [BZOJ3080]Minimum Variance Spanning Tree/[BZOJ3754]Tree之最小方差树
[BZOJ3080]Minimum Variance Spanning Tree/[BZOJ3754]Tree之最小方差树 题目大意: 给定一个\(n(n\le50)\)个点,\(m(m\le1000 ...
- 【bzoj3754】Tree之最小方差树 最小生成树
题目描述 给出一张无向图,求它的一棵生成树,使得选出的所有边的方差最小.输出这个最小方差. 输入 第一行两个正整数N,M 接下来M行,每行三个正整数Ui,Vi,Ci N<=100,M<=2 ...
- 【BZOJ 3754】Tree之最小方差树
http://www.lydsy.com/JudgeOnline/problem.php?id=3754 核心思想:暴力枚举所有可能的平均数,对每个平均数排序后Kruskal. 正确的答案一定是最小的 ...
- 【BZOJ 3754】: Tree之最小方差树
题目链接: TP 题解: 都是骗子233,我还以为是什么神奇的算法. 由于边权的范围很小,最小生成树和最大生成树之间的总和差不会太大,所以可以枚举边权和,再直接根据方差建最小生成树,每次更新答案即可. ...
- 【枚举】【最小生成树】【kruscal】bzoj3754 Tree之最小方差树
发现,若使方差最小,则使Σ(wi-平均数)2最小即可. 因为权值的范围很小,所以我们可以枚举这个平均数,每次把边权赋成(wi-平均数)2,做kruscal. 但是,我们怎么知道枚举出来的平均数是不是恰 ...
- bzoj3754 Tree之最小方差树 最小生成树+推性质
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3754 题解 感觉这个思路挺神仙的. 后悔没有好好观察题目的数据范围,一直把 \(n\) 和 \ ...
随机推荐
- SWD下载调试填坑,SWD连接丢失问题解决
野火SWD下载器,设置好以后,第一次下载成功,莫名其妙丢失连接,发现在复位状态可以连接(惊奇) 网络上搜索到把Boot0和Boot1置高,就可以把程序下载到RAM里, 能下载以后就好办了,把程序里SW ...
- socket java 实例
简单的java socket 示例 一.搭建服务器端 a).创建ServerSocket对象绑定监听端口. b).通过accept()方法监听客户端的请求. c).建立连接后,通过输入输出流读取客户端 ...
- CentOS7.1安装 Vsftpd FTP 服务器
# yum install vsftpd 安装 Vsftpd FTP 编辑配置文件 ‘/etc/vsftpd/vsftpd.conf’ 用于保护 vsftpd. # vi /etc/vsftpd/vs ...
- iOS11 push控制器tabbar上移问题
解决方法 - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { // 如果有大 ...
- linux c编程:信号(二) alarm和pause函数
使用alarm函数可以设置一个定时器,在将来的某个时刻该定时器超时.当定时器超时后,产生SIGALRM信号.如果忽略或不捕捉此信号,则其默认动作是终止调用该alarm函数的进程 #include< ...
- python+NLTK 自然语言学习处理六:分类和标注词汇一
在一段句子中是由各种词汇组成的.有名词,动词,形容词和副词.要理解这些句子,首先就需要将这些词类识别出来.将词汇按它们的词性(parts-of-speech,POS)分类并相应地对它们进行标注.这个过 ...
- php7下 xhprof安装与使用
需要测试下 代码的性能,使用了 xhprof + xhgui 1. 下载xhprof, 这里下载吧 :https://github.com/longxinH/xhprof.git 2, 安装 cd x ...
- 使用apt-get 安装后的mysql 登录问题
当使用apt-get安装mysql后,ubuntu会自动生成一个用户名和密码.所以在第一次登陆时会报如下错误 ERROR 1045 (28000): Access denied for user 'd ...
- SAP 改表方法
SAP中直接修改表.视图的Tcode有SE16N和SM30. 1. SE16N修改表需要先输入命令&SAP_EDIT,回车左下角显示激活SAP编辑功能后,就可以对相应的表进行新增.删除.修改的 ...
- Write 语句
ABAP Write 语句 转载▼http://blog.sina.com.cn/s/blog_5ccd375b0100ghhi.html 1.Write 叙述 ABAP/4 用来在屏幕上输出数据 ...