UVA10228 模拟退火

题目链接:

https://www.luogu.org/problem/UVA10228

 

一眼看。很明显嘛,裸的模拟退火

什么?你不知道什么是模拟退火?出门请右转 https://www.cnblogs.com/btcadmire123A/articles/11248754.html

如果想要更好的游戏体验,  https://www.cnblogs.com/flashhu/p/8884132.html

所以::为什么是模拟退火的说?

看官请看:

给定一个N边形所有顶点坐标x,y,求其费马点到所有顶点距离和。费马点是指到多边形所有顶点距离和最小的点。

 

某大神说:我会计算平面几何+三分,复杂度优秀。 请您左转至题库切了他。

  在这里我提供的是随机化算法(模拟退火)。

    在我看来,退火明显比爬山算法好(虽然都属玄学),因为他有更大几率获得全局最优解,而非局部。

当然操作还是分为Calc与SA(Simulate Anneal)的啦。

此时寻找的解是此时的“费马点”到所有顶点的坐标距离(二维距离,非曼哈顿距离)。

calc操作表示此时解的费马距离(口胡定义,莫要见怪)并实时更新。

SA操作照样负责找随机解并judge更新否?

代码若下:

#include<cstring>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<ctime>
#include<algorithm>
#include<iostream>

using namespace std;

#define maxn 10050

int x[1005],y[1005],n,T;
double ansx,ansy,ans;

int read();
double calc(double a,double b);
void SA();
void work();

int main(){
    T=read();
    while(T--){
        n=read();
        for(int i=1;i<=n;i++)    x[i]=read(),y[i]=read();
        ansx=ansy=0;ans=calc(0,0);
        work();
        cout<<(int)(ans+0.5)<<endl;
        if(T) cout<<endl;
    }
}

int read(){
    int ans=0,f=1;char t;
    while(t<'0'||t>'9') {if(t=='-') f=-1;t=getchar();}
    while(t>='0'&&t<='9') ans=ans*10+t-'0',t=getchar();
    return ans*f;
}

double calc(double a,double b){
    double ret=0;
    for(int i=1;i<=n;i++) ret+=sqrt((x[i]-a)*(x[i]-a)+(y[i]-b)*(y[i]-b));
    return ret;
}

void SA(){
    double x=ansx,y=ansy;
    for(double Temp=50001;Temp>=0.00000001;Temp*=0.98){
        double nx=Temp*(rand()*2-RAND_MAX)+x;
        double ny=Temp*(rand()*2-RAND_MAX)+y;
        double nans=calc(nx,ny);
        double bet=nans-ans;
        if(bet<0) ans=nans,x=ansx=nx,y=ansy=ny;
        else if(exp(-bet/Temp)*RAND_MAX>rand()) x=nx,y=ny;
    }
}

void work(){
    for(int i=1;i<=15;i++) SA();
}

我才不会告诉你我没有UVA账号,不能提交。 我也不知道它能不能AC。

posted @ 2019-07-26 19:45  admire◢◤  阅读(441)  评论(0编辑  收藏  举报