题解:
模拟退火。
记得最后终止步数设置大一点,然后再原地跳几次,不然很容易GG。
#include <bits/stdc++.h>
typedef long double DB;
using namespace std;
inline unsigned int Rand() {
static unsigned int state0=19491001;
state0^=(state0<<13);
state0^=(state0>>17);
state0^=(state0<<5);
return state0;
}
inline int rd() {
char ch=getchar(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
const int N=1e4+50;
const DB PI=acos(-1.0);
struct P {
DB x,y;
P(DB x=0,DB y=0):x(x), y(y){}
friend inline P operator +(const P &a, const P &b) {return P(a.x+b.x,a.y+b.y); }
friend inline P operator -(const P &a, const P &b) {return P(a.x-b.x,a.y-b.y); }
inline DB dis() {return sqrt(x*x+y*y);}
}p[N],now,bst;
int n;
DB ans,lst,w[N];
inline DB calc(const P &tp) {
DB rs=0;
for(int i=1;i<=n;i++) rs+=w[i]*(p[i]-tp).dis();
return rs;
}
inline DB rnd() {
return (Rand()%10000)/10000.0;
}
int main() {
n=rd();
for(int i=1; i<=n; i++) p[i].x=rd(), p[i].y=rd(), w[i]=rd(), now.x+=p[i].x, now.y+=p[i].y;
now.x/=n; now.y/=n; bst=now;
ans=(lst=calc(now)); DB st=1e8;
for(;st>0.0001;st=st*0.988) {
P tp=now+P(st*(rnd()*2-1.0),st*(rnd()*2-1.0));
DB ta=calc(tp);
if(ta<ans) bst=tp,ans=ta;
if(ta<lst || (exp((lst-ta)/st))>rnd()) lst=ta,now=tp;
}
for(int i=1;i<=1000;i++) {
P tp=bst+P(st*(rnd()*2-1.0),st*(rnd()*2-1.0));
DB ta=calc(tp);
if(ta<ans) bst=tp,ans=ta;
}
printf("%.3f %.3f",(double)bst.x,(double)bst.y);
}