Zju 2419 Triangle [凸包] 解题报告
http://andyzh1314.ycool.com/post.1050679.html
Zju 2419 Triangle [凸包] 解题报告
算法是先寻找凸包,然后对凸包枚举其中一点,在枚举凸包中的另一点,第三点随着第二点的变化而变化。
我们知道最优三角形的三个点一定在凸包上,下面我们证明一下:
假设我们有最优三角形ABC中存在点不在凸包上,不妨设之为A,那么必然在凸包上存在三个点包含A点,过A点作BC的平行线l ,此平行线要么与凸包的一条边重合,那么这点可以算在凸包上,否则必有交点,那么凸包上必存在一点P与A在直线l的异侧。那么我们得到三角形PBC的面积大于三角形ABC的面积,三角形ABC不是最优三角形。
故三角形的三个顶点一定在凸包上。
我的程序如下:
PROGRAM p2319;
TYPE
PosType=record
x,y :Longint;
end;
VAR
n :Longint;
line :array[1..50000]of PosType;
ball :array[0..50000]of Longint;
PROCEDURE Change(var a,b:PosType);
var
temp :PosType;
begin
temp:=a;
a:=b;
b:=temp;
end;
PROCEDURE Readin;
var
min,i,num_miny :Longint;
begin
min:=9999999;
for i:=1 to n do
with line[i] do
begin
readln(x,y);
if y<min then
begin
min:=y;
num_miny:=i;
end;
end;
Change(line[1],line[num_miny]);
for i:=2 to n do
with line[i] do
begin
x:=x-line[1].x;
y:=y-line[1].y;
end;
with line[1] do
begin
x:=0;
y:=0;
end;
end;
Function compare(var a,b:PosType):Longint;
begin
compare:=a.y*b.x-a.x*b.y;
end;
PROCEDURE Sort(left,right:Longint);
var
mid,i,j :Longint;
key,temp :PosType;
begin
key:=line[left];
i:=left-1; j:=right+1;
repeat
repeat dec(j); until compare(line[j],key)<=0;
repeat inc(i); until compare(line[i],key)>=0;
if (i<j) then
begin
temp:=line[i];
line[i]:=line[j];
line[j]:=temp;
end else break;
until false;
if (j+1<right) then Sort(j+1,right);
if (left<i-1) then Sort(left,i-1);
end;
FUNCTION Check(v:Longint):Boolean;
var
a,b :PosType;
mul :Longint;
begin
with a do
begin
x:=line[ball[ball[0]-1]].x-line[ball[ball[0]]].x;
y:=line[ball[ball[0]-1]].y-line[ball[ball[0]]].y;
end;
with b do
begin
x:=line[v].x-line[ball[ball[0]]].x;
y:=line[v].y-line[ball[ball[0]]].y;
end;
if a.x*b.y-b.x*a.y>0 then Check:=true
else Check:=false;
end;
PROCEDURE Main;
var
i,j,k :Longint;
a,b,c :Longint;
temp :PosType;
ans,first,second :Extended;
Function area(var a,b,c:Longint):Extended;
begin
area:=abs(
(line[a].x-line[b].x) * (line[c].y-line[b].y)
-(line[a].y-line[b].y) * (line[c].x-line[b].x));
end;
begin
Sort(2,n);
ball[0]:=2;
ball[1]:=1;
ball[2]:=2;
for i:=3 to n do
begin
while check(i) do
dec(ball[0]);
inc(ball[0]);
ball[ball[0]]:=i;
end;
ans:=-1;
first:=0;
k:=0;
for i:=1 to ball[0] -2 do
begin
dec(k,200);
for j:=i+1 to ball[0] -1 do
begin
if (k<=j) then k:=j+1;
first:=area(ball[i],ball[j],ball[k]);
if first>ans then ans:=first;
while (k+1<=ball[0]) do
begin
second:=area(ball[i],ball[j],ball[k+1]);
if second<first then break;
inc(k);
first:=second;
if first>ans then ans:=first;
end;
end;
end;
{for i:=1 to n do
for j:=i+1 to n do
for k:=j+1 to n do if area(i,j,k)> ans then ans:=area(i,j,k);
}
ans:=ans / 2;
writeln(ans:0:2);
end;
BEGIN
readln(n);
while (n>0) do
begin
Readin;
Main;
readln(n);
end;
END.