BZOJ3680:吊打XXX(模拟退火)

传送门

题解:
模拟退火。

记得最后终止步数设置大一点,然后再原地跳几次,不然很容易GG。

#include <bits/stdc++.h>
typedef long double DB;
using namespace std;

inline unsigned int Rand() {
    static unsigned int state0=19491001;
    state0^=(state0<<13);
    state0^=(state0>>17);
    state0^=(state0<<5);
    return state0;
}
inline int rd() {
    char ch=getchar(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
    return i*f;
}

const int N=1e4+50;
const DB PI=acos(-1.0);

struct P {
    DB x,y;
    P(DB x=0,DB y=0):x(x), y(y){}
    friend inline P operator +(const P &a, const P &b) {return P(a.x+b.x,a.y+b.y); }
    friend inline P operator -(const P &a, const P &b) {return P(a.x-b.x,a.y-b.y); }
    inline DB dis() {return sqrt(x*x+y*y);}
}p[N],now,bst;

int n;
DB ans,lst,w[N];

inline DB calc(const P &tp) {
    DB rs=0;
    for(int i=1;i<=n;i++) rs+=w[i]*(p[i]-tp).dis();
    return rs;
}

inline DB rnd() {
    return (Rand()%10000)/10000.0;
}

int main() {
    n=rd(); 
    for(int i=1; i<=n; i++) p[i].x=rd(), p[i].y=rd(), w[i]=rd(), now.x+=p[i].x, now.y+=p[i].y;
    now.x/=n; now.y/=n; bst=now;
    ans=(lst=calc(now)); DB st=1e8;
    for(;st>0.0001;st=st*0.988) {
        P tp=now+P(st*(rnd()*2-1.0),st*(rnd()*2-1.0));
        DB ta=calc(tp);
        if(ta<ans) bst=tp,ans=ta;
        if(ta<lst || (exp((lst-ta)/st))>rnd()) lst=ta,now=tp;
    }
    for(int i=1;i<=1000;i++) {
        P tp=bst+P(st*(rnd()*2-1.0),st*(rnd()*2-1.0));
        DB ta=calc(tp);
        if(ta<ans) bst=tp,ans=ta;
    }
    printf("%.3f %.3f",(double)bst.x,(double)bst.y);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值