P1337 [JSOI2004]平衡点 / 吊打XXX 【模拟退火】
洛谷 P1337 -> Click Here
题意
有 \(n\) 个点在一个平面上,且第 \(i\) 个点对点 \(X\) 施一拉力 \(w_i\) ,寻找 \(X\) 的平衡位置
思路
模拟退火经典入门题目,虽然是单峰函数,但也可用退火解决
设初始点为每个点的平衡位置,进行模拟退火,寻找新点,查看当前位置是否更优或是否在一定可接受的概率内,逐渐降温,平衡点也逐渐精确
code
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define down 0.996
#define REP(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
struct edge{double x,y,w;} E[100005];
int n;
double ansx,ansy,answ;
double getde(double x,double y){
double r=0,dx,dy;
REP(i,1,n){
dx=x-E[i].x;
dy=y-E[i].y;
r+=sqrt(dx*dx+dy*dy)*E[i].w;
}
return r;
}
void sa(){
double t=4000;
while(t>1e-15){
double ex=ansx+(rand()*2-RAND_MAX)*t;
double ey=ansy+(rand()*2-RAND_MAX)*t;
double ew=getde(ex,ey);
double dw=ew-answ;
if(dw<0){
ansx=ex;
ansy=ey;
answ=ew;
}else if(exp(-dw/t)*RAND_MAX>rand()){
ansx=ex;
ansy=ey;
}
t*=down;
}
}
int main(){
scanf("%d",&n);
REP(i,1,n){
scanf("%lf%lf%lf",&E[i].x,&E[i].y,&E[i].w);
ansx+=E[i].x;
ansy+=E[i].y;
}
ansx/=n;
ansy/=n;
answ=getde(ansx,ansy);
int cnt=4;while(cnt--) sa();
printf("%.3lf %.3lf\n",ansx,ansy);
return 0;
}

浙公网安备 33010602011771号