1. 程式人生 > 其它 >洛谷 P1337 [JSOI2004]平衡點 / 吊打XXX(模擬退火)

洛谷 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;
}