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

时间:2023-03-10 06:24:51
题解:[JSOI2004]平衡点 / 吊打XXX

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

交了两面半。。。我怕是非洲大酋长

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include<ctime>
using namespace std; #define il inline
#define re register
#define ll long long
#define gc getchar()
inline int read()
{
re int x(0),f(1);re char c(gc);
while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
return f*x;
} const int N=10100;
const double D=0.98,eps=1e-15;
double n;
double x[N],y[N],w[N]; il double f(double p,double q)
{
double d=0;
for(int i=1;i<=n;++i)
d+=w[i]*sqrt((p-x[i])*(p-x[i])+(q-y[i])*(q-y[i]));
return d;
} double dx,dy,T,nx,ny,ns,ax,ay,as,ds; il void sa()
{
for(int i=1;i<=n;++i)
dx+=x[i],dy+=y[i];
dx/=n,dy/=n,ds=f(dx,dy);
T=101000;
while(T>eps)
{
nx=dx+((rand()*2)-RAND_MAX)*T;
ny=dy+((rand()*2)-RAND_MAX)*T;
ns=f(nx,ny);
if(ns<ds)
dx=nx,dy=ny,ds=ns;
else if(rand()<exp((ds-ns)/T)*RAND_MAX)
dx=nx,dy=ny,ds=ns;
T*=D;
if(ds<as) as=ds,ax=dx,ay=dy;
}
} int main()
{
srand(time(0));
n=read();
for(int i=1;i<=n;++i)
scanf("%lf%lf%lf",x+i,y+i,w+i);
ax=x[1],ay=y[1];as=f(x[1],y[1]);
sa(),sa(),sa(),sa();
printf("%.3lf %.3lf",ax,ay);
return 0;
}