解题思路
学习了一下玄学算法--模拟退火,首先要求平衡处,也就是求势能最小的地方,就是求这个点到所有点的距离*重量最小。剩下的几乎是模拟退火的板子了。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int MAXN = 10005; const double delta = 0.98; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int n,x[MAXN],y[MAXN],w[MAXN]; double ans=1e18,t,ansx,ansy,sx,sy; double calc(double X,double Y){ double ret=0,cx,cy; for(register int i=1;i<=n;i++){ cx=X-x[i];cy=Y-y[i]; ret+=sqrt(cx*cx+cy*cy)*w[i]; } return ret; } void SA(){ double xx=ansx,yy=ansy,X,Y,now,D; t=2000; while(t>1e-14){ X=xx+((rand()<<1)-RAND_MAX)*t; Y=yy+((rand()<<1)-RAND_MAX)*t; now=calc(X,Y);D=now-ans; if(D<0){ xx=X,yy=Y;ans=now; ansx=xx,ansy=yy; } else if(exp(-D/t)*RAND_MAX>rand()) xx=X,yy=Y; t*=delta; } } void Solve(){ ansx=(double)sx/n,ansy=(double)sy/n; SA();SA();SA(); } int main(){ srand(19260817);srand(rand());srand(rand()); n=rd(); for(int i=1;i<=n;i++) x[i]=rd(),y[i]=rd(),w[i]=rd(),sx+=x[i],sy+=y[i]; Solve(); printf("%.3lf %.3lf",ansx,ansy); return 0; }