zoukankan      html  css  js  c++  java
  • Luogu P1337 [JSOI2004]平衡点 / 吊打XXX

    一道入门模拟退火的经典题,还是很考验RP的

    首先我们发现神TM这道题又和物理扯上了关系,其实是一道求广义费马点的题目

    首先我们可以根据物理知识得到,当系统处于平衡状态时,系统的总能量最小

    又此时系统的总能量是等于各个物体的重力势能,在质量一定时,即要求物体离地最近,离桌子最远

    那么,也就是绳子在桌子上的距离尽量的小,即要求(sum_{i=1}^n m_icdot dist_{i,x})最小

    (以上物理部分推导摘于pym‘s blog

    然后考虑退火,我们先选取一个初始位置(一般取所有点坐标的平均数方便收敛)

    然后每次退火时给坐标随机一个增量(要随温度降低而减少,并注意需要取的),并计算新的解的答案

    同时按照一般的模拟退火流程考虑是否接受解并且降温即可

    PS:本题极大的考验调参能力,本人Luogu由于机子快,交了几发就A了。TM的BZOJ老爷机一直在WA和TLE直接徘徊,最后好像9900+MSA了(时限10S)。

    CODE

    #include<cstdio>
    #include<cstdlib>
    #include<cctype>
    #include<cmath>
    #include<ctime>
    using namespace std;
    typedef double DB;
    const int N=1005;
    const DB EPS=1e-30,dlt=0.981;
    struct data
    {
        int x,y,w;
    }a[N];
    int n; DB ans_x,ans_y,ave_x,ave_y,ans;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch; int flag=1; while (!isdigit(ch=tc())) flag=ch^'-'?1:-1;
        while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); x*=flag; 
    }
    inline DB calc(DB x,DB y)
    {
        register int i; DB tot=0;
        for (i=1;i<=n;++i)
        tot+=(DB)sqrt((x-a[i].x)*(x-a[i].x)+(y-a[i].y)*(y-a[i].y))*a[i].w;
        return tot;
    }
    inline void Simulate_Anneal(DB x,DB y)
    {
        DB T=500,res=calc(x,y); 
        for (;T>EPS;T*=dlt)
        {
            DB xx=x+(rand()*2-RAND_MAX)*T,yy=y+(rand()*2-RAND_MAX)*T,now=calc(xx,yy);
            if (now<ans) ans=now,ans_x=xx,ans_y=yy;
            if (now<res||exp((res-now)/T)>(DB)rand()/RAND_MAX) res=now,x=xx,y=yy;
        }
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        register int i,t=50; srand(time(0)); read(n);
        for (i=1;i<=n;++i)
        {
            read(a[i].x); read(a[i].y); read(a[i].w);
            ave_x+=a[i].x; ave_y+=a[i].y;
        }
        ans_x=ave_x=(DB)ave_x/n; ans_y=ave_y=(DB)ave_y/n; ans=calc(ans_x,ans_y);
        while (t--) Simulate_Anneal(ave_x,ave_y);
        return printf("%.3lf %.3lf",ans_x,ans_y),0;
    }
    
  • 相关阅读:
    正则表达式
    eclipse python开发环境搭建
    python中的构造函数和析构函数
    socket网络编程中的同步,异步,阻塞式,非阻塞式,有何联系与区别?
    Render和template?
    什么是MemCache
    python下 help()使用方法
    Tornado模块分类和各模块之间的关系
    把python项目部署到centos里
    Jquery对回复者添加匿名评论选项
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9545110.html
Copyright © 2011-2022 走看看