ATcoder ABC 338 D: 这是一份模拟退火的代码:
#include<cmath>
#include<ctime>
#include<cstdio>
#include<climits>
#include<iostream>
#define N 200001
using namespace std;
int n,m,a[N];
typedef long long ll;
ll ans=2147483647;
double eps=1e-4;
ll p(ll x){
if(x<1)return 1;
if(x>n)return n;
return x;
}
ll calc(ll x){
ll ans=0;
for(int i=2;i<=m;i++){
if(x>min(a[i-1],a[i])&&x<max(a[i],a[i-1]))ans+=abs(n-max(a[i],a[i-1]))+min(a[i],a[i-1]);
else ans+=abs(a[i]-a[i-1]);
}
return ans;
}
int RND(){
return 2*rand()-RAND_MAX;
}
void solve(){
double T=1e6;
ll x=rand()%n+1;
ll now=calc(x);
ans=min(ans,now);
while(T>eps){
ll y=p(x+(ll)(T*RND())%(n+1ll));
ll qq=calc(y);
double delta=qq-now;
if(qq<ans)ans=qq;
if(now<qq||exp(-delta/T)*RAND_MAX>rand())x=y,now=qq;//,printf("%d %d\n",x,now)
T*=0.985;
}
}
int main(){
srand(19260817);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)scanf("%d",&a[i]);
while((double)clock()/CLOCKS_PER_SEC<1.7)solve();
printf("%lld",ans);
}
对于这个数据:
163054 10
62874 19143 77750 111403 29327 56303 6659 18896 64175 26369
他输出388911
而当把注释掉那部分代码写到 now=qq后面,如下:
if(now<qq||exp(-delta/T)*RAND_MAX>rand())x=y,now=qq,printf("%d %d\n",x,now);
即对于每一次转移都进行观测,那么输出就会变成390009
就离谱,为什么?波粒二象性?