P1337 [JSOI2004]平衡点 / 吊打XXX

P1337 [JSOI2004]平衡点 / 吊打XXX

模拟退火

模拟退火入门题

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cstdlib>
#include<ctime>
#include<cmath>
#define re register
using namespace std;
template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;}
template <typename T> inline T max(T &a,T &b) {return a>b ?a:b;}
template <typename T> inline void read(T &x){
    char c=getchar(); x=0; bool f=1;
    while(!isdigit(c)) f= !f||c=='-' ? 0:1,c=getchar();
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    x= f ? x:-x;
}
template <typename T> inline void output(T x){
    if(!x) {putchar(48); return ;}
    if(x<0) putchar('-'),x=-x;
    int wt[50],l=0;
    while(x) wt[++l]=x%10,x/=10;
    while(l) putchar(wt[l--]+48);
}
typedef double db;
struct data{int x,y,w;}a[1002];
int n; double ans=1e15,ax,ay;
inline db calc(db X,db Y){ //计算该状态下的解->根据题意修改
    db res=0;
    for(re int i=1;i<=n;++i){
        db d1=a[i].x-X,d2=a[i].y-Y;
        res+=sqrt(d1*d1+d2*d2)*(db)a[i].w; //累加重力势能
    }return res;
}
inline void smt(){
    db f1=ax,f2=ay;
    for(db t=2000;t>1e-14;t*=0.993){ //初温,末温,降温系数。自由修改
        db r1=f1+((rand()<<1)-RAND_MAX)*t;
        db r2=f2+((rand()<<1)-RAND_MAX)*t;
        db _val=calc(r1,r2),delta=_val-ans;
        if(delta<0) ans=_val,f1=ax=r1,f2=ay=r2;
        else if(exp(-delta/t)*RAND_MAX>rand()) f1=r1,f2=r2; //以一定的概率接受非最优解
    }
}
int main(){
    srand(19260817); srand(rand()); srand(rand());
    read(n);
    for(re int i=1;i<=n;++i) read(a[i].x),read(a[i].y),read(a[i].w),ax+=a[i].x,ay+=a[i].y;
    ax=ax/(db)n; ay=ay/(db)n; //从平均值开始更接近最优解
    while((double)clock()/CLOCKS_PER_SEC<0.8) smt(); //卡时。时间定义 0.8s < 1s - 一次模拟退火的耗时 - 以下代码的耗时 (自行把握)
    printf("%.3lf %.3lf",ax,ay);
    return 0;
}

 

posted @ 2018-09-29 10:01  kafuuchino  阅读(248)  评论(0编辑  收藏  举报