zoukankan      html  css  js  c++  java
  • P5544 【[JSOI2016]炸弹攻击1】

    模拟退火

    (多扶老奶奶过马路,可以增长(RP)偶)

    模拟退火主要是求最优解的一种方法

    模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。
    ----某度某科

    monituihuo

    这是模拟退火的模拟图

    模拟退火就是在降温过程中随机新的答案,并判断答案是否更优,如果更优,就接受新的结果,否则就以一定的概率接受新的答案

    温度越高,解的变化量越大,随着温度的逐渐降低,解的变化量也渐渐变小,并越发集中在最优解附近

    模拟退火在洛谷日报上有详细的解释,如果不会模拟退火可以先去康康

    就是这

    我们首先看这个题,我们直接模拟退火就好了

    但要注意一点(exp(- del / temp) * RAND_MAX < rand())

    这里是小于(因为这是求最大值,如果求最小值就用大于就好了)

    然后就是注意这个题求最大值就(OK)

    #include<bits/stdc++.h>
    using namespace std;
    #define eps 1e-10//看脸的东西
    #define xita 0.9972//同上
    const int N = 15, M = 1005;
    double n, m, R, sumx, sumy, a[M], b[M], ans, ax, ay;
    struct node{
        double x, y, r;
    }s[N];
    double dis(double x, double y, double xx, double yy){
        return sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy));
    }//求距离
    double query(double x, double y){//计算答案
        double res = 0, d = R;
        for(int i = 1; i <= n; i ++){
            d = min(d, dis(x, y, s[i].x, s[i].y) - s[i].r);
        }//求炸弹最大的爆炸半径
        for(int i = 1; i <= m; i ++){
            if(dis(x, y, a[i], b[i]) <= d) res ++;
        }//统计能炸到的僵尸
        return res;
    }
    void SA(){//模拟退火
        double ansx = ax, ansy = ay;
        double temp = 2605;//初始温度,一般为2000~3000左右(自己定)
        while(temp > eps){
            double xx = ansx + ((rand() << 1) - RAND_MAX) * temp;
            double yy = ansy + ((rand() << 1) - RAND_MAX) * temp;
            //rand()一组新的坐标
            double nowans = query(xx, yy);//当前的答案
            double del = nowans - ans;//求差值
            if(del > 0){//如果更优,就更新答案
                ax = xx; ay = yy;
                ansx = xx; ansy = yy;
                ans = nowans;
            }else{
                if(exp(- del / temp) * RAND_MAX < rand()){//否则就以一个概率接受这个答案,(这个概率特别小)
                    ansx = xx;
                    ansy = yy;
                }
            }
            temp *= xita;//降温
        }
    }
    void cz(){
        ax = sumx / m; ay = sumy / m;//开始最好用平均值跑
        for(int i = 1; i <= 6; i ++){//多跑几遍模拟退火
            SA();
        }
    }
    int main(){
        srand(1e9 + 7);//随机种子
        scanf("%lf %lf %lf", &n ,&m, &R);   
        for(int i = 1; i <= n; i ++){
            scanf("%lf %lf %lf", &s[i].x, &s[i].y, &s[i].r);
        }
        for(int i = 1; i <= m; i ++){
            scanf("%lf %lf", &a[i], &b[i]);        
            sumx += a[i]; sumy += b[i];//求总和
        }
        cz();
        printf("%.0lf
    ", ans);//输出,答案要求为整数,我定义的double,所以直接保留0位小数就好了
        return 0;
    }
    

    希望此篇题解能够对您起到帮助(不要像我一样,交了好几十遍)

  • 相关阅读:
    ActiveMQ中JMS的可靠性机制
    ActiveMQ中Broker的应用与启动方式
    ActiveMQ支持的传输协议
    ActiveMQ常见消息类型
    Oracle体系结构及备份(十六)——bg-ckpt
    PHP自学之路---雇员管理系统(1)
    UVa11187
    给Android组件添加事件一个很好用的方法
    【项目那些事儿】项目哪些事儿?
    struts2对拦截器使用带实例
  • 原文地址:https://www.cnblogs.com/wsdslll/p/13710184.html
Copyright © 2011-2022 走看看