BZOJ.3680. Hanging XXX (simulated annealing/hill climbing algorithm)

topic link

Simulated Annealing (SA):
(1) Initialize a temperature (sufficiently large), initial solution state S, and the number of iterations for each T value.
(2) For i=1,...,L, do steps (3) to (7).
(3) Generate a new solution S'.
(4) Calculate Δt=C(S')-C(S), where C(S) is the evaluation function.
(5) If Δt<0, accept the new solution S' as the current solution; otherwise, accept S' as the current solution with the probability of exp(-Δt'/(kT)) (k is the Boltzmann constant, generally regardless of it ?)
(6) If the termination condition is satisfied, output the current solution as the optimal solution and end the program.
The termination condition is usually to terminate the algorithm when several consecutive new solutions are not accepted.
(7) T gradually decreases, and T->0, go to (2).

//1028kb    6256ms
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define D (0.96)//as big as possible?
#define Rand() ((rand()<<1)-RAND_MAX)
const int N=10005;

int n;
struct Node{
    int w;
    double x,y;
}p[N];

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
inline double Sqr(double x){
    return x*x;
}
inline double Dis(double x,double y,int i){
    return sqrt(Sqr(x-p[i].x)+Sqr(y-p[i].y));
}
double Calc(double x,double y)
{
    double res=0;
    for(int i=1; i<=n; ++i)
        res+=Dis(x,y,i)*p[i].w;//i->dis*w[i] i对答案产生dis*w[i]的影响 
    return res;
}
void SA()
{
    double ansx=0,ansy=0,ans;
    for(int i=1; i<=n; ++i)
        ansx+=p[i].x*p[i].w, ansy+=p[i].y*p[i].w;
    ansx/=n, ansy/=n, ans=Calc(ansx,ansy);
    for(int Time=1; Time<=5; ++Time)//多次!需要记录ans及now。
    {//一次大概要1000次。
        double T=1000,nowx=ansx,nowy=ansy,now=Calc(ansx,ansy),res,xx,yy;
        while(T>1e-12)
        {
//          xx=ansx+T*(2*(rand()%Max)-Max),yy=ansy+T*(2*(rand()%Max)-Max);//x(y)+[-Max,Max-2] 不能只是用坐标的最大值。。delta应该够大些。
            xx=nowx+T*Rand(),yy=nowy+T*Rand();//x(y)+[-RAND_MAX,RAND_MAX-1]
            res=Calc(xx,yy);
            if(res<ans) ans=res, ansx=xx, ansy=yy;
            if(res<now)
                nowx=xx, nowy=yy, now=res;
            else if(exp((now-res)/T)*RAND_MAX>rand())//exp(-delta/T)>rand()/RAND_MAX
                nowx=xx, nowy=yy;
            T*=D;
        }
    }
    printf("%.3lf %.3lf",ansx,ansy);
}

int main()
{
    srand(20180501);
    n=read();
    for(int i=1; i<=n; ++i) p[i].x=read(),p[i].y=read(),p[i].w=read();
    SA();
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325002705&siteId=291194637