RT,模拟退火WA#8,其它点都过去了,调参怎么都调不出来(用半径的方差退火)
代码:
#include <cstdio>
#include <cmath>
#include <ctime>
#define N 20
#define ld double//long double
ld p[N][N];
ld temp[N],now[N],best[N];
ld mn[N],mx[N];
int n;
void read()
{
scanf("%d",&n);
for(int i=0;i<=n;i++)
for(int j=0;j<n;j++)
{
scanf("%lf",&p[i][j]);
now[j]+=p[i][j];
if(p[i][j]<mn[j]) mn[j]=p[i][j];
if(p[i][j]>mx[j]) mx[j]=p[i][j];
}
for(int i=0;i<n;i++)
now[i]=best[i]=now[i]/n;
}
ld C(ld a[N])
{
//O(n^2)
static ld temp[N];
int q=n+1;
ld sum=0,sqsum=0;
for(int i=0;i<=n;i++)
{
ld tmp=0;
for(int j=0;j<n;j++)
tmp+=(a[j]-p[i][j])*(a[j]-p[i][j]);
sum+=(temp[i]=sqrt(tmp));
}
sum/=q;
ld b=0;
for(int i=0;i<=n;i++)
{
ld tmp=temp[i];
b+=(tmp-sum)*(tmp-sum);
}
return b;
}
#define RND (rand()/(double)RAND_MAX)
#define kb 1.38e-23 //玻尔兹曼常数
inline bool accept(ld now,ld t,double te)
{
return t<now||exp((now-t)/te/kb)>RND;
}
void sa()
{
const double TEMP=1e20;
const double eps=1e-28;
const double COOL=0.997;
double t=TEMP;
while(t>eps)
{
for(int i=0;i<n;i++)
{
temp[i]=now[i]+(RND-0.5)*sqrt(t);
if(temp[i]<mn[i]) temp[i]=mn[i];
if(temp[i]>mx[i]) temp[i]=mx[i];
}
if(accept(C(now),C(temp),t))
{
for(int i=0;i<n;i++) now[i]=temp[i];
if(C(now)<C(best))
for(int i=0;i<n;i++) best[i]=now[i];
}
t*=COOL;
}
}
#define TIME (clock()/(double)CLOCKS_PER_SEC)
int main()
{
read();
srand(0xdeadbeef);
srand(rand());
while(TIME<0.9)sa();
for(int i=0;i<n;i++) printf("%.3lf ",now[i]);
//printf("\n%lf\n",C(now));
return 0;
}
(验证码RAID)