这道题调了好久,果然非洲人是得不到眷顾的吗。。。


本题采用模拟退火解决。

模拟退火是一种简洁明了而又高效的近似算法,基本上可以套到任何求最优解的题目上去。

它的原理是模拟物理中金属退火的现象,凭借选手逆天的RP跳出局部最优解,来到全局最优解。

比较常用的近似算法还有爬山和遗传,但是我个人觉得没太大必要掌握(像我这种脸黑的选手有一次遗传算法WA52。。)。


模拟退火总体就是一个持续降温的流程。

在降温的过程中,坐标随机跳动的范围会越变越小。

当然,为了防止搞错,我们每一次都会以一定概率接受一个比较奇怪的解,这一点有些类似遗传算法中的突变。

inline void simulateAnneal(){
double x=ansx,y=ansy;t=5000;
while(t>1e-14){
double X=x+((rand()<<1)-RAND_MAX)*t,Y=y+((rand()<<1)-RAND_MAX)*t;
double now=calcEnergy(X,Y),dist=now-ans;
if(dist<0){
ansx=x=X,ansy=y=Y,ans=now;
}else if(exp(-dist/t)*RAND_MAX>rand())x=X,y=Y;
t*=delta;
}
}

这里t代表温度,它会一直递减。

然后每一次我们会根据t的值(控制范围)随机跳一个新的解。

求一下它的值,看一下值能不能接受。

假如这个值不能接受,那就以一定概率接受一个奇奇怪怪的解,选择解的方法遵循Metropolis准则(我也不知道这是什么玩意别问我)。

求值的流程因题而异,总之就是一个衡量解的标准。

template<typename T>inline T calcEnergy(T x,T y){
T tmp=0;
for(register int i=1;i<=n;++i){
T disx=x-a[i].x,disy=y-a[i].y;
tmp+=sqrt(disx*disx+disy*disy)*a[i].val;
}
return tmp;
}

主要的部分大概就这么多了,其他要注意的无非就是常数什么的了。

M_sea大佬用的常数是

delta=0.993
t=2000
loop=5

(loop指的是运行次数)

然而这个常数对于脸黑的我来说比较窒息,所以做了一点小调整,最后是

delta=0.9932
t=5000
loop=5

最后,AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
namespace StandardIO{
template<typename T>inline void read(T &x){
x=0;T f=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
x*=f;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x*=-1;
if(x>=10)write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve{
const int N=1010;
const double delta=0.9932; struct SA{
private:
int n,sumx,sumy;
double ans=1e18,t;
struct node{
int x,y,val;
}a[N];
template<typename T>inline T calcEnergy(T x,T y){
T tmp=0;
for(register int i=1;i<=n;++i){
T disx=x-a[i].x,disy=y-a[i].y;
tmp+=sqrt(disx*disx+disy*disy)*a[i].val;
}
return tmp;
}
inline void simulateAnneal(){
double x=ansx,y=ansy;t=5000;
while(t>1e-14){
double X=x+((rand()<<1)-RAND_MAX)*t,Y=y+((rand()<<1)-RAND_MAX)*t;
double now=calcEnergy(X,Y),dist=now-ans;
if(dist<0){
ansx=x=X,ansy=y=Y,ans=now;
}else if(exp(-dist/t)*RAND_MAX>rand())x=X,y=Y;
t*=delta;
}
} public:
SA(){}
~SA(){} double ansx,ansy;
inline void init(){
srand(19260817),srand(rand()),srand(rand());
read(n);
for(register int i=1;i<=n;++i){
read(a[i].x),read(a[i].y),read(a[i].val);
sumx+=a[i].x,sumy+=a[i].y;
}
}
template<typename T>inline void SimulateAnneal(T times){
ansx=(double)sumx/n,ansy=(double)sumy/n;
for(register int i=1;i<=times;++i)simulateAnneal();
}
}ljz; inline void solve(){
ljz.init();
ljz.SimulateAnneal(5);
printf("%.3lf %.3lf",ljz.ansx,ljz.ansy);
}
}
using namespace Solve;
int main(){
solve();
}

题解 P1337 【[JSOI2004]平衡点 / 吊打XXX】的更多相关文章

  1. 洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX 解题报告

    P1337 [JSOI2004]平衡点 / 吊打XXX 题目描述 有 \(n\) 个重物,每个重物系在一条足够长的绳子上.每条绳子自上而下穿过桌面上的洞,然后系在一起.\(X\)处就是公共的绳结.假设 ...

  2. 洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX

    洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX 点击进入FakeHu的模拟退火博客 神仙模拟退火...去看fakehu的博客吧...懒得写了... 因为精度问题要在求得的最优解附近(大约 ...

  3. 洛谷P1337 [JSOI2004]平衡点 / 吊打XXX(模拟退火)

    题目描述 如图:有n个重物,每个重物系在一条足够长的绳子上.每条绳子自上而下穿过桌面上的洞,然后系在一起.图中X处就是公共的绳结.假设绳子是完全弹性的(不会造成能量损失),桌子足够高(因而重物不会垂到 ...

  4. P1337 [JSOI2004]平衡点 / 吊打XXX 模拟退火

    链接 https://www.luogu.org/problemnew/show/P1337 思路 交了好多发,都是wrong 初始值取平均数就1A了 真的是玄学的算法 代码 // luogu-jud ...

  5. [洛谷P1337][JSOI2004]平衡点 / 吊打XXX

    题目大意:有$n$个重物,每个重物系在一条绳子上.所有绳子系在一起,问绳结最终平衡于何处. 题解:$NOIP$前学学模拟退火,但发现我脸好黑啊... 卡点:脸黑 C++ Code: #include ...

  6. 题解:[JSOI2004]平衡点 / 吊打XXX

    这个题目算是一个模拟退火的板子题 物重一定,绳子越短,重物越低,势能越小,势能又与物重成正比 使得$\sum_{i=1}^nd[i]*w[i]$也就是总的重力势能最小,可以使得系统平衡 交了两面半.. ...

  7. P1337 [JSOI2004]平衡点 / 吊打XXX

    题目描述 如图:有n个重物,每个重物系在一条足够长的绳子上.每条绳子自上而下穿过桌面上的洞,然后系在一起.图中X处就是公共的绳结.假设绳子是完全弹性的(不会造成能量损失),桌子足够高(因而重物不会垂到 ...

  8. Luogu P1337 [JSOI2004]平衡点 / 吊打XXX

    一道入门模拟退火的经典题,还是很考验RP的 首先我们发现神TM这道题又和物理扯上了关系,其实是一道求广义费马点的题目 首先我们可以根据物理知识得到,当系统处于平衡状态时,系统的总能量最小 又此时系统的 ...

  9. 洛谷P1337 [JSOI2004]平衡点 / 吊打XXX(模拟退火)

    传送门 先坑着,联赛活着回来的话我就写(意思就是我绝对不会写了) //minamoto #include<cstdio> #include<cmath> #include< ...

  10. LUOGU P1337 [JSOI2004]平衡点 / 吊打XXX(模拟退火)

    传送门 解题思路 学习了一下玄学算法--模拟退火,首先要求平衡处,也就是求势能最小的地方,就是求这个点到所有点的距离*重量最小.剩下的几乎是模拟退火的板子了. #include<iostream ...

随机推荐

  1. 《你又怎么了我错了行了吧》【Alpha】Scrum meeting 2

    第二天 日期:2019/6/15 前言: 第2次会议在9C-405召开 进行第一天工作的检查,开始第二天工作的安排和学习 1.1 今日完成任务情况以及明天任务安排 姓名 当前阶段任务 下一阶段任务 刘 ...

  2. 【codeforces 807D】Dynamic Problem Scoring

    [题目链接]:http://codeforces.com/contest/807/problem/D [题意] 给出n个人的比赛信息; 5道题 每道题,或是没被解决->用-1表示; 或者给出解题 ...

  3. C和C++ const的声明差异

    当在C源代码文件中将变量声明为const时,可以通过以下方式实现: const int i = 2; 然后,可以在另一个模块中使用此变量,如下表示: extern const int i; 但若要获取 ...

  4. BA--三相异步电机_星三角降压启动

    星一三角启动就是一种简单方便的降压启动方式,同时还可通过手动和自动操作控制方式实现. 星三角起动的优点还是很显著的,因为同任何别的减压起动器相比较,其结构最简单,价格也最便宜 除此之外,星三角起动方式 ...

  5. 解决VTune错误PMU resources currently being used by another profiling tool or process

    错误信息: When I ran Hardware Event-based Sampling Analysis 0, it showed the ERROR: Collection failed Co ...

  6. redis代码解析-事务

    redis 的事务相关的几个命令分别为 watch multi exec. watch 可以监控一个变量在事务开始执行之前是否有被修改.使用方式为: WATCH key [key ...] 在redi ...

  7. Oracle 用户管理(一)

    1     创建用户     create user @username identified by @password     比如:create user aobama identified by ...

  8. 程序猿的量化交易之路(18)--Cointrader之Event实体(6)

    转载需注明: 事件,是Esper的重要概念. 这里我们定义个事件类.它是Temporal实体的派生类. 不过对Temporal简单的包装.其代码例如以下: package org.cryptocoin ...

  9. mysql安装出错cannot create windows service for mysql.error:0

    配置时最后一步出现不能启动mysql 解决成功的办法:[MySQL] Could not start the service MySQL 解决方法 安装mysql 5.1.33,在运行Server I ...

  10. 【iOS开发系列】XIB IBOutlets use strong or weak ?

    有人问.在ARC下,IBOutlets究竟应该定义成strong 还是 weak ?支持这个答案的人最多.答案仅是摘自官方文档的一个片段: From a practical perspective, ...