某题 模拟退火

阳光穿透心脏的1/2处 2023-10-10 10:21 154阅读 0赞

为了防止某天忘了默默的屯下来…

参考的skyh的代码而写的(虽然大部分都一样吧….)

1716445-20190808151438949-1156557137.png

网上褪的话:增加十倍的初温与末温比值只会增加约25%的迭代次数,而往0.9…99的后面加个9会增加十倍的运行时间。(t==1000不是跑了1000遍的)

#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
const double cg=0.973;
const int maxn=100005;
int n,h[maxn];
int turn[maxn],x;
ll ans;
inline int abs(int x){return (x^(x>>31))-(x>>31);}
ll check(int pos)//模拟位置通过位置知高度再去算代价
{
for(register int i=1;i<=pos;++i) turn[i]=h[i]+pos-i;
for(register int i=pos+1;i<=n;++i) turn[i]=h[i]+i-pos;
int mid=(1+n)>>1;//奇数个显然,偶数个的话左右两个数选谁代价同因为列式子左右两边的两个数和抵消了该数的贡献
nth_element(turn+1,turn+mid,turn+n+1);
x=turn[mid];
if(xx) x=n-pos+1; //这两个if是把不合法的情况(0)排除正确性是因为当x,它们时我把x换过去不就是换了个离中位数最近的吗。所以是对的
ll cost=0;
for(register int i=1;i<=n;++i) cost+=abs(x-turn[i]);
return cost;
}
inline int read()
{
int t=0; char ch=getchar();
while(ch<’0’||ch>’9’) ch=getchar();
while(ch>=’0’&&ch<=’9’) t=(t<<3)+(t<<1)+(ch^48),ch=getchar(); return t; \} int main() \{ srand(time(0)); n=read(); for(register int i=1;i<=n;++i) h\[i\]=read(); double T=985,dt=1e-5; int tmp,now=(1+n)>>1;
ll turnans,nowans,dta;
nowans=check(now); ans=nowans;
while(T>dt)
{
tmp=now+(2ll*rand()-0x7fffffff)*T*0.000001;//保证rand数的随机摆动性左右摆动,rand出来的可能很大*0.000001
if(T<1.00) tmp=max(tmp,1),tmp=min(tmp,n);//别rand出去 else tmp=(tmp%n+n-1)%n+1;//在确保正数情况下rand一个1-n的数 turnans=check(tmp),dta=turnans-nowans; if(turnansrand()) nowans=turnans,now=tmp;//nowans只是我们用来找最优解的一个东西
if(turnans<ans) ans=turnans;//维护最终结果。
T*=cg;//退火降温
}
printf(“%lld”,ans);
return 0;
}

转载于:https://www.cnblogs.com/three-D/p/11321107.html

发表评论

表情:
评论列表 (有 0 条评论,154人围观)

还没有评论,来说两句吧...

相关阅读

    相关 模拟退火

    Summary 退火总结.退火其实不难...难的是怎么调参. 贡献两页提交才只有\\(55pts\\)的经历真是惨不忍睹.这就是调参的艰难. 主要就是这么几个参数

    相关 模拟退火算法(代码)

    在实际日常中,人们会经常遇到如下问题:在某个给定的定义域![X][]内,求函数![f(x)][f_x]对应的最优值。此处以最小值问题举例(最大值问题可以等价转化成最小值问题),

    相关 模拟退火入门*3

    CTS2019Day2T1出了道可以乱搞的的计算几何,我辛辛苦苦写了280多行,结果就给了我10分,这不气炸了。 据我分析,可能是因为我没有学过模拟退火,乱搞是真的乱搞,儿