[JSOI]平衡点

题目

luogu1337

bzoj3680

题解

模拟退火第一波题,真的是...非常玄学的一种算法 Orz

网上讲解挺多的,而我又比较弱,当然是不写题解了

鉴于当时我什么都看不懂,我的代码有比较详细的注释(水平有限,语文也不好,希望大佬们不要婊我),找找网上关于此算法的思想和实现,代码看不懂的可以看看我的(os:感觉自己真膨胀)

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath> 
#define N 10005
#define inf 1000000000
using namespace std; 

int n;
double w[N],px,py,En;

struct node
{
    double x,y;
    node(){}
    node(double xx,double yy) {x=xx;y=yy;}
}p[N],ans;
node operator + (node a,node b) {return node(a.x+b.x,a.y+b.y);}

double dis(node a,node b)//计算距离 
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double calc(node now)
{
    double cnt=0;
    for(int i=1;i<=n;i++) cnt+=w[i]*dis(now,p[i]);//计算当前状态下的总能量 
    if(cnt<En)//若当前状态更稳定 ,更新 
    {
        En=cnt;
        ans=now;
    }
    return cnt;//返回当前状态的总能量 
}

double Rand() {return (double)(rand()%10000)/10000.0;}//将rand()范围限制在0~1 
node get_SA()
{
    node now=ans,nxt;
    double t=100000,DE;
    while(t>0.0001)//当状态稳定至一定值后退出循环 
    {
        nxt=now+node(t*(Rand()*2-1),t*(Rand()*2-1));//随机选择加一个点(t不断缩小,随机点的范围也在逐渐缩小)
        DE=calc(now)-calc(nxt);//计算当前点与随机点的能量差值 
        if(DE>0||exp(DE/t)>Rand())//若随机点更优,替换当前点,同时有一定几率让并不较优的随机点替换当前点 
            now=nxt;
        t*=0.97;//???
    }
    for(int i=1;i<=1000;i++)//多算几遍更新ans,我觉得这个“几遍”比较玄学,算多了要T,算少了又WA
    {
        nxt=ans+node(t*(Rand()*2-1),t*(Rand()*2-1));
        calc(nxt); 
    }
}

int main()
{
    srand(19970815);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf%lf",&p[i].x,&p[i].y,&w[i]);
        px+=p[i].x;py+=p[i].y;
    }
    ans=node(px/n,py/n);//先将答案暂定为几何中心 
    En=calc(ans);//初始能量 
    get_SA();
    printf("%.3lf %.3lf",ans.x,ans.y);
    return 0;
}

转载于:https://www.cnblogs.com/XYZinc/p/7419791.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值