洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX(模拟退火)
传送门
解题思路
特别狗的一道题
根据重力势能最小时平衡(??),可以进行模拟退火。
其他的套板子行了。
然后我就写挂了(交了24次)
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<iomanip>
using namespace std;
const int maxn=1005;
const double delta=0.996;
int n;
double ans,ansx,ansy,sumx,sumy;
struct node{
double x,y,w;
}a[maxn];
double cal(double x,double y){
double ans=0;
for(int i=1;i<=n;i++){
double d=(x-a[i].x)*(x-a[i].x)+(y-a[i].y)*(y-a[i].y);
d=sqrt(d);
ans+=d*a[i].w;
}
return ans;
}
void SA(){
double t=3000,x=ansx,y=ansy;
while(t>1e-15){
double newx=x+(rand()*2-RAND_MAX)*t,newy=y+(rand()*2-RAND_MAX)*t;
double res=cal(newx,newy);
double cha=res-ans;
if(cha<0) ans=res,ansx=x=newx,ansy=y=newy;
else if(exp(-cha/t)*RAND_MAX>rand()) x=newx,y=newy;
t*=delta;
}
}
int main(){
ios::sync_with_stdio(false);
srand(time(NULL));
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y>>a[i].w;
sumx+=a[i].x;
sumy+=a[i].y;
}
ansx=sumx/n;
ansy=sumy/n;
ans=1e18;
while((double)clock()/CLOCKS_PER_SEC<=0.85) SA();
cout<<fixed<<setprecision(3)<<ansx<<" "<<ansy;
return 0;
}