UVA10228 A Star not a Tree?

https://vjudge.net/problem/UVA-10228

模拟退火平面坐标系中的板题

注意使用rand()而不是mt19937 rnd(),因为rand()范围比较小,比较适合做这种坐标范围比较小的题,用mt19937*当前温度T加进x和y中就会变化非常大,很难得到最优解,rand()在windows中范围是32767,非常合适.

upd:可以使用dis(rnd)来修改范围,就能过了。根据不同的题修改不同的范围,还能返回实数。

模拟退火过不去的时候,可以增大初始温度,增大delta的值,增加模拟退火次数,减小停止温度等方法

#include<bits/stdc++.h>
using namespace std;
mt19937 rnd(time(0));
uniform_int_distribution<> dis(1,100000);

const double delta=0.996;
const int maxl=110;

int n,cas;
struct point
{
	double x,y;
}a[maxl];
double ansx,ansy,ans,t;
int tx[9]={0,1,0,-1,0,1,1,-1,-1};
int ty[9]={0,0,1,0,-1,1,-1,1,-1};

inline void prework()
{
	scanf("%d",&n);
	double sumx=0,sumy=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%lf%lf",&a[i].x,&a[i].y);
		sumx+=a[i].x;sumy+=a[i].y;
	}
	ansx=sumx/n;ansy=sumy/n; 
}

inline double calc(double x,double y)
{
	double res=0,dx,dy;
	for(int i=1;i<=n;i++)
	{
		dx=x-a[i].x;dy=y-a[i].y;
		res+=sqrt(dx*dx+dy*dy);
	}
	return res;
}

inline void anneal()
{
	double x=ansx,y=ansy,nx,ny;
	t=3000;int f;
	while(t>1e-20)
	{
		f=1;if(dis(rnd)&1) f=-1;
		nx=x+(f*dis(rnd))*t;
		f=1;if(dis(rnd)&1) f=-1;
		ny=y+(f*dis(rnd))*t;
		double now=calc(nx,ny);
		if(now<ans)
		{
			ansx=nx;ansy=ny;
			x=nx;y=ny;
			ans=now;
		}
		else if(exp(-(now-ans)/t)>1.0*dis(rnd)/100000)
			x=nx,y=ny;
		t*=delta;
	}
}

inline void mainwork()
{	
	ans=calc(ansx,ansy);
	anneal();
	anneal();
	anneal();
}

inline void print()
{
	long long d=ans;
	if(ans-d>=0.5)
		d++;
	 printf("%lld\n",d);
}

int main()
{
	srand(time(0));
	int t;
	scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
		if(cas!=t)
			puts("");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/107750785