菜鸡求助模拟退火(WA#8)
查看原帖
菜鸡求助模拟退火(WA#8)
298051
xkcdjerry楼主2020/12/26 13:15

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)

2020/12/26 13:15
加载中...