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 2

1 0

0 2

0 1


Output

0.0000 0.0000
0.0000 2.0000
1.0000 2.0000
1.0000 0.0000

【注4】全部共线时不限定栈大小会导致栈元素小于2,导致RTE。

【注5】pascal请用extended。同时写一个cmp函数。a>b改写成a-b>1e-12,依此类推。

附赠几组数据(删减版):

#1

Input

15
372048554 194840794
1493722368 1609046412
764185136 846253213
1495038584 704170204
239709973 1230989664
908965419 1067337718
1296315630 717326987
576635090 1685913746
1232082109 1060706659
653622963 1534768490
448977811 741758128
244213649 77154157
911904634 230031831
1614797846 889031095
241142922 1949120387

Output

239709973.0000 1230989664.0000
241142922.0000 1949120387.0000
1493722368.0000 1609046412.0000
1614797846.0000 889031095.0000
1495038584.0000 704170204.0000
911904634.0000 230031831.0000
244213649.0000 77154157.0000

#2

Input

4

1 1

2 2

3 3

4 4

Output

1.0000 1.0000
4.0000 4.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.
原文地址:https://www.cnblogs.com/htfy/p/3067884.html