zoukankan      html  css  js  c++  java
  • 【BZOJ3680】吊打XXX-模拟退火

    测试地址:吊打XXX
    做法:本题需要用到模拟退火。
    假设所有绳子的长度都相同,而且绳长都等于天花板到地面的高度,那么一个物品和地面的距离就等于绳结到对应的孔的距离。又因为重力势能和物品距地面的高度和物品本身的质量有关,而一个系统的总重力势能最小时,就是这个系统的平衡状态,于是我们转化成了求一对(x,y),使得:
    i=1n(xxi)2+(yyi)2wi
    最小。我们发现我们找不到任何方法在多项式时间内求出这个最小值,这个时候就要用模拟退火来解决了。
    模拟退火是一种启发式搜索,它的算法过程是仿照现实中的退火效应设计的。算法过程如下:
    首先,设定一个初始温度T和一组初始解。
    接下来,重复这一步直到温度下降到一个阈值内:随机移动解的位置,移动的距离随着T的减小而减小,如果新的位置上的函数值比原先更优,则直接将解转移到这个位置,否则计算出一个转移的概率p,有p的概率转移到这个位置,最后温度T下降。
    最后,在已得到的最优解的周围进行小范围的随机走动,如果比当前解更优则转移,逐渐逼近最优解。
    中间这个p按照现实中的退火效应,一般设置为exp(EnowEnextT)exp(x)exEnow,Enext分别表示当前的函数值和随机移动后位置的函数值。注意到当Enow>Enext时,p>1,即表示一定转移,否则0<p<1,符合概率的定义。当然这个式子是在求最小值的时候用的,求最大值时在括号里加个负号即可。
    至于其他参数的设置,不同的题目的最好参数各不相同,需要根据实际情况调参,才能既满足时间要求,也能得到一个比较优的解。这个算法一般在提交答案试题中常用。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n;
    double x[10010],y[10010],w[10010];
    double ansx=0.0,ansy=0.0,D,ans;
    
    double Rand()
    {
        return (double)(rand()%10000)/10000.0;
    }
    
    double calc(double nowx,double nowy)
    {
        double sum=0.0;
        for(int i=1;i<=n;i++)
            sum+=sqrt((nowx-x[i])*(nowx-x[i])+(nowy-y[i])*(nowy-y[i]))*w[i];
        if (sum<D) ansx=nowx,ansy=nowy,D=sum;
        return sum;
    }
    
    void work()
    {
        double dE,T=100000.0,nowx=ansx,E=D,nowy=ansy,newx,newy;
        while(T>0.001)
        {
            newx=nowx+T*(2.0*Rand()-1.0);
            newy=nowy+T*(2.0*Rand()-1.0);
            dE=E-calc(newx,newy);
            if (exp(dE/T)>Rand())
                nowx=newx,nowy=newy,E-=dE;
            T*=0.97;
        }
        for(int i=1;i<=1000;i++)
        {
            nowx=ansx+T*(2.0*Rand()-1.0);
            nowy=ansy+T*(2.0*Rand()-1.0);
            calc(nowx,nowy);
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&x[i],&y[i],&w[i]);
            ansx+=x[i],ansy+=y[i];
        }
    
        ansx/=(double)n,ansy/=(double)n,D=calc(ansx,ansy);
        work();
        printf("%.3lf %.3lf",ansx,ansy);
    
        return 0;
    }
  • 相关阅读:
    跟随标准与Webkit源码探究DOM -- 获取元素之querySelector,querySelectorAll
    跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName
    跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByTagName
    跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByName
    跟随标准与Webkit源码探究DOM -- 获取元素之getElementById
    原生DOM探究 -- NodeList v.s. HTMLCollection
    Jira 在流程节点中每个状态权限设置
    Eureka集群配置
    Linux下搭建 redis
    python框架django中结合vue进行前后端分离
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793367.html
Copyright © 2011-2022 走看看