[BZOJ3680]吊打XXX

来源:互联网 发布:管家婆 远程数据库 编辑:程序博客网 时间:2024/05/22 03:12

原题地址

经典物理模型…

资料详见http://bakser.blog.163.com/blog/static/23589413220147161124294/

我用的是模拟退火(参考的是http://www.mamicode.com/info-detail-213016.html).

大概做法:
1.取所有点横、纵坐标的平均值做为起始点(如果是随机数据目测可以起到很好的效果).
2.以当前点为圆心,半径r画圆,在圆内随机取一点作为新点(r为参数),然后模拟退火就可以了.

AC code:

#include <cstdio>#include <cstdlib>#include <ctime>#include <cmath>typedef double llf;const int N=10010;int n;int x[N],y[N],g[N];llf cal(llf X,llf Y){    llf sum=0;    for(int i=1;i<=n;i++) sum+=(llf)sqrt((X-x[i])*(X-x[i])+(Y-y[i])*(Y-y[i]))*g[i];    return sum;}llf move(llf t){    llf flg=(rand()&1)?1:-1;    return t+flg*0.001*(rand()%100+1);}void work(){    llf X,Y,T=10000;    for(int i=1;i<=n;i++){X+=x[i];Y+=y[i];}    X/=(llf)n;Y/=(llf)n;    while(T>0.1){        T*=0.9;        llf TX=move(X),TY=move(Y);        if(cal(TX,TY)<cal(X,Y)||rand()%10000<T){X=TX;Y=TY;}    }    printf("%.3lf %.3lf\n",X,Y);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d%d%d",&x[i],&y[i],&g[i]);    work();    return 0;}
0 0