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

    预备概念:

      金属退火:将金属缓慢加热到一定温度,保持足够时间,然后以适宜速度冷却

      温度:一个逐渐减小的参数,表示接受次优解的概率

    模拟退火是一种解决复杂问题的算法,相当于贪心,但以一个逐渐减小的该率接受次优解,当然,该次优解距最优解越远,同等温度下被接受的概率也就越小

    参考洛谷日报上某巨佬代码(主要是参考在何时接受次优解,生成正负随机数的技巧以及如何确定退火初值),打了一下洛咕P1337

    接受次优解:

      exp (  ( ans            -         cur  )    /   temp)   *        RAND_MAX             >      rand()

           当前最优解              当前解    温度             定值,参考cstdlib                 随机数

    调参失败时具体技巧:

      1:开始的随机种子一定要多随机几次(玄学???)

      2:调节温度下降的速度(至少0.99以上QWQ)

      3:合理调整最终答案的处值,模拟退火算法可以多执行几次,判定算法结束的条件精度高

      4:用一些玄学数字:19******

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #define ll long long
    #define ri register int
    
    const int MAXN = 1005;
    const int SA_TIME = 4;
    const double DELTA = 1e-14;
    
    ll read(){
        ll x = 0; int zf = 1; char ch = ' ';
        while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
        if (ch == '-') zf = -1, ch = getchar();
        while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
    }
    
    int x[MAXN], y[MAXN], w[MAXN];
    int n;
    
    double ansx = 0, ansy = 0, ans=1e18;
    const double delta = 0.993;
    
    inline double getDis(double x1, double y1, double x2, double y2){
        return (sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
    }
    
    inline double cacEny(double curx,double cury){
        double sum = 0;
        for (ri i = 1; i <= n; ++i)
            sum += getDis(x[i], y[i], curx, cury) * w[i];
        return sum;
    }
    
    inline int getRand(){
        //需要返回负数,故特殊处理rand函数
        return ((rand() << 1) - RAND_MAX);
    }
    
    inline void SA(){
        double sx = ansx, sy = ansy, curx, cury;
        double temp = 1926;
        while (temp >= DELTA){
            if (temp < 10)
                temp = temp - 1 + 1;
            curx = sx + getRand() * temp, cury = sy + getRand() * temp;
            double cur_eny = cacEny(curx, cury);
            if (cur_eny < ans){
                sx = curx, sy = cury;
                ansx = curx, ansy = cury, ans = cur_eny;
            }//接受次优解 
            else {
                if (exp((ans - cur_eny) / temp) * RAND_MAX > rand())
                    sx = curx, sy = cury;
            }
            temp *= delta;
        }
    }
    
    inline void Solve() {
        int sumx = 0, sumy = 0;
        for (ri i = 1; i <= n; ++i)
            sumx += x[i], sumy += y[i];
        ansx=(double)(sumx) / n, ansy=(double)(sumy) / n;
        for (ri i = 1; i <= SA_TIME; ++i)
            SA();
    }
    
    int main() {
        srand(71806291); srand(rand()); srand(rand()); srand(rand());
        n = read();
        for (ri i = 1; i <= n; ++i)
            x[i] = read(), y[i] = read(), w[i] = read();
        Solve();
        printf("%.3f %.3f
    ", ansx, ansy);
        return 0;
    }

    未经博主允许禁止转载

    参考资料:
      洛谷日报2018年9月#60 地址 作者:M_sea

      exp函数 地址 作者:百度百科

  • 相关阅读:
    ASP.NET 生成静态html页之扩展(按年月目录)
    一个.net实现的ubb类
    win2003 安全设置
    ffmpeg参数使用说明
    C#正则表达式参考
    asp.net防图片盗链HttpHandler
    自定义datalist分页(转)
    asp.net中DateTime使用(转)
    缓存依赖性dependencies
    查看服务器日志文件的作用
  • 原文地址:https://www.cnblogs.com/linzhengmin/p/10629910.html
Copyright © 2011-2022 走看看