1. 程式人生 > >bzoj3680: 吊打XXX(模擬退火)

bzoj3680: 吊打XXX(模擬退火)

exp span long long 接下來 main mage 要求 概率 spa

  題目要求

技術分享  

  最小(dis表示繩結到點i的距離),就是個廣義費馬點的題,模擬退火裸題QAQ

  模擬退火就是優化後的爬山算法,一開始先隨機一個平均點,接下來如果隨機到的點比當前點劣,溫度比較高的話也有幾率跳過去,這樣就能跳出一個局部最優解,隨著溫度降低,跳到劣點的概率越來越小

  好喵喵的算法!

  (這題好像黃學長直接爬山算法也過了,模擬退火賊慢T^T

技術分享
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio> 
#include
<cmath> #define ll long long using namespace std; const int maxn=500010,inf=1e9; int n; double ans,ansx,ansy; double x[maxn],y[maxn],g[maxn]; double dis(double x1,double y1,double x2,double y2) {return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));} double cal(double xx,double yy) { double
sum=0; for(int i=1;i<=n;i++)sum+=g[i]*dis(xx,yy,x[i],y[i]); if(sum<ans)ans=sum,ansx=xx,ansy=yy; return sum; } double Rand(){return rand()%1000/1000.0;} void sa(double T) { double nowx=ansx,nowy=ansy; while(T>1e-3) { double nextx=nowx+T*(Rand()*2-1);
double nexty=nowy+T*(Rand()*2-1); double dE=cal(nowx,nowy)-cal(nextx,nexty); if(dE>0||exp(dE/T)>Rand())nowx=nextx,nowy=nexty; T*=0.991; } for (int i=1;i<=1000;i++) { double nextx=ansx+T*(Rand()*2-1); double nexty=ansy+T*(Rand()*2-1); cal(nextx,nexty); } } int main() { srand(2333333); scanf("%d",&n);ans=2333333333333333333ll; for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&x[i],&y[i],&g[i]); ansx+=x[i];ansy+=y[i]; } ansx/=n;ansy/=n;sa(100000); printf("%.3lf %.3lf",ansx,ansy); return 0; }
View Code

bzoj3680: 吊打XXX(模擬退火)