Tyvj1462 细节凸包
P1462终于过了……说起来只是一个简单的凸包却交了7次,足见此题数据之严。
我使用的是graham scan。先找到y坐标最小,若y相同x最小点【注1】的坐标作为起始点P0,显然其他点与P0的极角属于[0,pi](此极角用arctan计算,特殊处理x=0与(x<0) and (y=0)时【注2】。注意pascal的arctan返回值是(-pi/2,pi/2)……)。按极角从大到小,若极角相同则按至P0点距离由小到大【注3】排序。
处理工作完成后,将P0与P1压入栈,之后循环处理P2~Pn-1若 栈顶 - I 在 栈顶-1 - 栈顶 向量的左侧或平行(你应该知道什么叫做叉积)则退栈,注意限定Stacksize>=2【注4】。最后将I压入栈。
之后找题目要求的找到起始点开始输出即可。注意精度【注5】。
【注1】
网上的graham scan 教程均这么认为,但经测试若按本算法没有x限制亦可。
【注2】
RTE&WA了请参照此两者。分别为pi/2和 pi。尤其是后者容易忘记考虑。
【注3】
由于之后两向量共线即退栈,要保证一条线上的点最远点能得以保留,则其应(在这些共线点中)最后处理。
Input 5 0 0 1 21 0 0 2 0 1 |
Output 0.0000 0.0000 |
【注4】全部共线时不限定栈大小会导致栈元素小于2,导致RTE。
【注5】pascal请用extended。同时写一个cmp函数。a>b改写成a-b>1e-12,依此类推。
附赠几组数据(删减版):
Input 15 |
Output 239709973.0000 1230989664.0000 |
Input 4 1 1 2 2 3 3 4 4 |
Output 1.0000 1.0000 |
Code:
program p1462; Const eps=1e-15; Type Point=record x,y:extended; end; Vector=Point; Var a,b:array[0..100002] of point; ans:array[0..100002] of longint; n,i,low,top:longint; Function len(a:vector):extended;inline;begin len:=sqrt(sqr(a.x)+sqr(a.y)); end; Function Dot(a,b:vector):extended;inline;begin dot:=a.x*b.x+a.y*b.y; end; Function cos(a,b:vector):extended;inline;begin cos:=dot(a,b)/len(a)/len(b); end; Function cross(a,b:vector):extended;inline;begin cross:=a.x*b.y-a.y*b.x; end; Function cmp(a:extended):longint;inline;begin if a>eps then exit(1);if a<-eps then exit(-1);exit(0); end; Function minus(a,b:vector):vector;inline;begin minus.x:=a.x-b.x;minus.y:=a.y-b.y; end; Function cos(A:vector):extended;inline;begin cos:=a.x/len(a); end; Function angle(A:vector):extended;inline;var y:extended;begin if cmp(a.x)=0 then exit(pi/2);if (cmp(a.x)<0) and (cmp(a.y)=0) then exit(pi); y:=arctan(a.y/a.x);if cmp(y)<0 then exit(y+pi) else exit(y); end; Procedure qsort(l,r:longint); var i,j:longint; x,y:point; begin i:=l;j:=r;x:=b[(l+r) div 2]; repeat while (cmp(angle(minus(b[i],b[1]))-angle(minus(x,b[1])))>0) or ((cmp(angle(minus(b[i],b[1]))-angle(minus(x,b[1])))=0) and (len(minus(b[i],b[1]))<len(minus(x,b[1])))) do inc(i); while (cmp(angle(minus(b[j],b[1]))-angle(minus(x,b[1])))<0) or ((cmp(angle(minus(b[j],b[1]))-angle(minus(x,b[1])))=0) and (len(minus(b[j],b[1]))>len(minus(x,b[1])))) do dec(j); if i<=j then begin y:=b[i]; b[i]:=b[j]; b[j]:=y; inc(i); dec(j); end; until i>j; if l<j then qsort(l,j); if i<r then qsort(i,r); end; Procedure push(P:longint); begin inc(top); ans[top]:=p; end; begin readln(n); for i:=1 to n do readln(a[i].x,a[i].y); low:=1; for i:=2 to n do if (a[i].y<a[low].y) or ((a[i].y=a[low].y) and (a[i].x>a[low].x)) then low:=i; top:=1; for i:=1 to n do if i<>low then begin inc(top); b[top]:=a[i]; end; b[1]:=a[low]; qsort(2,n); top:=0; push(1);push(2); for i:=3 to n do begin while (cmp(cross(minus(b[ans[top]],b[ans[top-1]]),minus(b[i],b[ans[top]])))>=0) and (top>=2) do dec(top); push(i); end; low:=1; for i:=2 to top do if (b[ans[i]].x<b[ans[low]].x) or ((b[ans[i]].x=b[ans[low]].x) and (b[ans[i]].y<b[ans[low]].y)) then low:=i; for i:=low to top do writeln(b[ans[i]].x:0:4,' ',b[ans[i]].y:0:4); for i:=1 to low-1 do writeln(b[ans[i]].x:0:4,' ',b[ans[i]].y:0:4); end.