/*
1 温度(步长)
初始温度T0--根据搜索空间范围看 --比如搜索维度1e5,则可以初始化为一半5*1e4(保证都可以搜到)
终止温度TE--1e-5(可调)
衰减系数T=T*0.999(可调 TLE就往下调0.95 0.9)
2 每次迭代在当前点邻域范围内随机取一个点x',计算邻域点函数值f(x')与当前点函数值f(x)的差Δ=|f(x)-f(x')|
2.1 Δ<0 跳到新点 x=x'
2.2 Δ>0 有一定概率跳到新点 x=x' 概率和Δ呈反比 p = e^(-Δ/T) Δ越大 p越小
同时随着T随迭代变小,p整体趋势减小
3 降低局部最优解概率的方法:
3.1 重复随机次数 局部最优概率=0.99 做1000次依然局部最优概率4e-5
3.2 分块模拟退火-OIwiki
本题
simulate-annual()
{
随机一个初始点
for(T=10000;T>1e-4;T=T*0.99) x,y<10000 步长初始化为10000
{
在当前点周围随机一个点
Δ=f(x')-f(x)
if(Δ)跳到新点
}
}
比赛时通过卡时(从大往小调迭代次数直到时间不超过1e8) 定迭代次数
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
#define x first
#define y second
using namespace std;
typedef pair<double, double> PDD;
const int N = 110;
int n;
PDD q[N];
double ans = 1e8;
double rand(double l,double r)
{
return (double) rand() / RAND_MAX*(r-l)+l;
}
double get_dist(PDD a,PDD b)
{
double dx=a.x-b.x;
double dy=a.y-b.y;
return sqrt(dx*dx+dy*dy);
}
double calc(PDD p)
{
double res=0;
for(int i=0;i<n;i++)
res+=get_dist(p,q[i]);
ans=min(res,ans);
return res;
}
void simulate_annual()
{
PDD cur(rand(0,10000),rand(0,10000));
for(double t=1e4;t>1e-4;t*=0.9)
{
PDD ne(rand(cur.x-t,cur.x+t),rand(cur.y-t,cur.y+t));
double dt=calc(ne)-calc(cur);
if(exp(-dt/t)>rand(0,1))cur=ne;
// 当dt<0时 exp(-dt/t)>1必然跳
// 当dt>0时 exp(-dt/t) in (0,1)有一定概率跳
}
}
int main()
{
cin >> n;
for(int i=0;i<n;i++)scanf("%lf%lf", &q[i].x, &q[i].y);
for(int i=0;i<100;i++)simulate_annual();
printf("%.0lf\n",ans);
return 0;
}