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