【模拟退火】poj3301

很嫩的时候就听说过模拟退火可以做npc问题,我那个崇拜啊,一直不敢动这种神级算法,今天玩了玩发现太imba了!

 

poj3301题目大意:平面上有N个点,求一个可以覆盖所有点的面积最小的正方形。

 

使用模拟退火就是枚举旋转角,逐渐减小步长逼近答案。

具体我有个比较漂亮的实现,假设方向向量为(a,b),那么面积为:

(max{a*x[i]+b*y[i]}-min{a*x[i]+b*y[i]})2/(a2+b2);当然,这个值还要在(a,b)和(-b,a)中取个max,因为是正方形两个相互垂直的方向嘛。

 

突发奇想:这道题可不可以做到立体空间中去呢?嗯,这个好玩。

 

无悬念的0ms了:

 

program poj3301; type real=extended; const fx:array[0..1] of longint=(1,-1); fy:array[0..1] of longint=(-1,1); var x,y:array[0..30] of real; task,i,j,k,n:longint;ok:boolean; t,e,tp,sx,sy,tx,ty,len,dis:real; function cal(a,b:real):real;var i:longint;min,max,t:real; begin max:=-1e30;min:=-max; for i:=1 to n do begin t:=a*x[i]+b*y[i]; if t>max then max:=t; if t<min then min:=t; end; cal:=sqr(max-min)/(a*a+b*b); end; begin readln(task);e:=1e-10; for task:=1 to task do begin readln(n); for i:=1 to n do readln(x[i],y[i]); sx:=100;sy:=0;tp:=1; len:=cal(sx,sy);t:=cal(sy,-sx); if t>len then len:=t; while tp>e do begin ok:=true; while ok do begin ok:=false; for i:=0 to 1 do begin tx:=sx+fx[i]*sy*tp; ty:=sy+fy[i]*sx*tp; dis:=cal(tx,ty);t:=cal(ty,-tx); if t>dis then dis:=t; t:=sqrt(1e4/(tx*tx+ty*ty)); tx:=tx*t;ty:=t*ty; if dis<len-e then begin ok:=true;len:=dis; sx:=tx;sy:=ty; end; end; end; tp:=tp/2; end; writeln(len:0:2); end; end.

你可能感兴趣的:(算法)