[板子]模拟退火

 1 #include<bits/stdc++.h>
 2 #define N 100005
 3 #define int long long
 4 using namespace std;
 5 const double eps=1e-5;
 6 double delta=0.956,fj=1;
 7 int n,ret,s[N],h[N];
 8 inline int _abs(int x){return x<0?-x:x;}
 9 int calc(int pos,int height){
10     int ans=0;
11     if(height<max(pos,n-pos))height=max(pos,n-pos);
12     for(int i=1;i<=n;++i)ans+=_abs(h[i]-_abs(height-_abs(i-pos)));
13     return ans;
14 }
15 int check(int pos){
16     for(int j=1;j<=n;++j)s[j]=h[j]+_abs(pos-j);
17     int mid=1+n>>1;
18     nth_element(s+1,s+mid,s+n+1);
19     return calc(pos,s[mid]);
20 }
21 void simulate_annealing(){
22     double T=1000;
23     int now=1+n>>1;
24     int tmpans=check(now);
25     while(T>eps){
26         int u=now+(2ll*rand()-RAND_MAX)*T*0.00001;
27         if(T<fj)u=max(u,1ll),u=min(u,n);
28         else u=(u%n+n-1)%n+1;
29         int newans=check(u);
30         int D=newans-tmpans;
31         ret=min(ret,newans);
32         if(newans<tmpans||(double)exp(-D/T)*(double)RAND_MAX>(double)rand())
33             tmpans=newans,now=u;
34         T*=delta;
35     }
36 }
37 signed main(){
38     srand((unsigned)time(0));
39     scanf("%lld",&n);
40     for(int i=1;i<=n;++i)scanf("%lld",&h[i]);
41     ret=0x7fffffffffffffff;
42     simulate_annealing();
43     printf("%lld",ret);
44 }

 

posted @ 2019-08-08 11:37  _xuefeng  阅读(40)  评论(0编辑  收藏  举报