Description
二维平面坐标系中有N个点。
从N个点选择3个点,问有多少选法使得这3个点形成直角三角形。
Input
第一行包含一个整数N(3<=N<=1500),表示点数。
接下来N行,每行包含两个用空格隔开的整数表示每个点的坐标,坐标值在-10^9到10^9之间。
每个点位置互不相同。
Output
输出直角三角形的数量。
Sample Input
输入1:
3
4 2
2 1
1 3
输入2:
4
5 0
2 6
8 6
5 7
输入3:
5
-1 1
-1 0
0 0
1 0
1 1
Sample Output
输出1:
1
输出2:
0
输出3:
7
分析
这个解释起来比较麻烦,请自己看英文或代码。英文题解
大概就是枚举一个点和别的点连边,然后算这条线的斜率(见斜率)。
然后就把斜率排序,枚举可能垂直的两条的边(可以用一个性质,垂直的两条边的斜率乘积为-1),就可以了。
代码
const max=1500;
type
ray=record
dx,dy:int64;
jpwang:longint;
end;
var
i,j,k,n:longint;
x:array[1..max] of longint;
y:array[1..max] of longint;
g:array[1..max] of ray;
temp:array[1..max] of ray;
num:array[0..3] of longint;
ans:longint;
procedure turn(var r:ray);
var
temp:int64;
begin
temp:=r.dx;
r.dx:=r.dy;
r.dy:=-temp;
r.jpwang:=(r.jpwang+1) mod 4;
end;
procedure qsort(lo,hi:longint);
var
mid:longint;
i,j,k:longint;
begin
if lo<>hi
then
begin
mid:=(lo+hi) div 2;
qsort(lo,mid);
qsort(mid+1,hi);
i:=lo;
j:=mid+1;
k:=lo;
while (i<=mid) and (j<=hi) do
begin
if g[i].dy*g[j].dx<g[j].dy*g[i].dx
then
begin
temp[k]:=g[i];
i:=i+1;
end
else
begin
temp[k]:=g[j];
j:=j+1;
end;
k:=k+1;
end;
while i<=mid do
begin
temp[k]:=g[i];
i:=i+1;
k:=k+1;
end;
while j<=hi do
begin
temp[k]:=g[j];
j:=j+1;
k:=k+1;
end;
for i:=lo to hi do
g[i]:=temp[i];
end;
end;
begin
readln(n);
for i:=1 to n do
readln(x[i],y[i]);
ans:=0;
for i:=1 to n do
begin
for j:=1 to n do
begin
g[j].jpwang:=0;
g[j].dx:=x[j]-x[i];
g[j].dy:=y[j]-y[i];
if i=j
then
begin
g[j].jpwang:=g[1].jpwang;
g[j].dx:=g[1].dx;
g[j].dy:=g[1].dy;
end
else
while not ((g[j].dx>0) and (g[j].dy>=0)) do
turn(g[j]);
end;
qsort(2,n);
j:=2;
while j<=n do
begin
fillchar(num,sizeof(num),0);
k:=j;
while (k<=n) and (g[j].dy*g[k].dx=g[k].dy*g[j].dx) do
begin
num[g[k].jpwang]:=num[g[k].jpwang]+1;
k:=k+1;
end;
j:=k;
ans:=ans+num[0]*num[1];
ans:=ans+num[1]*num[2];
ans:=ans+num[2]*num[3];
ans:=ans+num[3]*num[0];
end;
end;
writeln(ans);
end.