T3 三角形(triangle)
问题描述
小熊和小猫都喜欢三角形,因为三角形很稳定。
小熊和小猫都喜欢平等,因为一段感情只有双方是平等的,才能长久。
小熊和小猫都喜欢直角,因为直角象征着规整。
所以,小熊和小猫最喜欢等腰直角三角形。
小熊和小猫有
N
N
N 个二维平面上的点,她们想知道,从中挑出三个,组成等腰直角三角形的方案数是多少。
输入格式
第一行一个整数
N
N
N ,表示点数。
接下来
N
N
N 行,第
i
i
i 行是
x
i
x_i
xi ,
y
i
y_i
yi ,表示第
i
i
i 个点的坐标是
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi)。
输出格式
一行一个整数,表示答案。
输入样例
40
1
1 0
1 1
0 0
输出样例
4
样例解释
有四种可能的三角形,分别是
(
1
,
2
,
3
)
;
(
1
,
2
,
4
)
;
(
1
,
3
,
4
)
;
(
2
,
3
,
4
)
(1,2,3);(1,2,4);(1,3,4);(2,3,4)
(1,2,3);(1,2,4);(1,3,4);(2,3,4)。
数据范围
对于所有数据,保证
1
≤
n
≤
3000
,
0
≤
x
i
,
y
i
≤
1
0
9
1\le n\le 3000,0\le x_i,y_i\le 10^9
1≤n≤3000,0≤xi,yi≤109 。由于坐标都是整数,不存在精度误差问题。
思路:
枚举等腰直角三角形的斜边,每次判断直角顶点存不存在,时间复杂度 O ( n 2 ) O(n^2) O(n2) 。
找直角顶点先旋转,后放缩
可以用 unordered_map 。
注意储存结构体的写法:
-
重载等号:
inline friend bool operator == (const Point u,const Point v){ return eql(u.x,v.x)&&eql(u.y,v.y); }
-
设置 hash 函数:
struct NodeHash { inline size_t operator () (const Node u) const{ return u.x*113+u.y; } };
注意不能存 double ,要出精度问题!
size_t 相当于 int
代码:
#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
#define in Read()
#define int long long
inline char ch(){
static char buf[1<<21],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}
inline int in{
int s=0,f=1;char x;
for(x=ch();x<'0'||x>'9';x=ch()) if(x=='-') f=-1;
for( ;x>='0'&&x<='9';x=ch()) s=(s<<1)+(s<<3)+(x&15);
return f==1?s:-s;
}
const int A=1e4+5;
const double pi=acos(-1.0);
const double EPS=1e-3;
inline bool eql(double x,double y){
if(fabs(x-y)<EPS) return 1;
return 0;
}
int n;
struct Point{
double x,y;
Point (double u=0,double v=0){
x=u,y=v;
}
inline friend bool operator == (const Point u,const Point v){
return eql(u.x,v.x)&&eql(u.y,v.y);
}
inline friend Point operator + (const Point u,const Point v){
return Point (u.x+v.x,u.y+v.y);
}
inline friend Point operator - (const Point u,const Point v){
return Point (u.x-v.x,u.y-v.y);
}
inline friend Point operator * (const Point u,double v){
return Point (u.x*v,u.y*v);
}
inline friend Point operator / (const Point u,double v){
return Point (u.x/v,u.y/v);
}
inline friend double operator & (const Point u,const Point v){
return u.x*v.x+u.y*v.y;
}
inline friend double operator ^ (const Point u,const Point v){
return u.x*v.y-u.y*v.x;
}
}p[A];
struct Node{
int x,y;
Node (double u=0,double v=0){
x=u,y=v;
}
inline friend bool operator == (const Node u,const Node v){
return (u.x==v.x)&&(u.y==v.y);
}
};
struct NodeHash {
inline size_t operator () (const Node u) const{
return u.x*113+u.y;
}
};
tr1::unordered_map <Node,int,NodeHash> ma;
int ans=0;
inline Node point_to_node(Point u){
Node v;
v.x=(int)(u.x+0.5),v.y=(int)(u.y+0.5);
if(eql(u.x,v.x)&&eql(u.y,v.y)) return v;
return Node(1e9+53,1e9+47);
}
inline Point rotate(Point u,double v){
return Point (u.x*cos(v)-u.y*sin(v),u.y*cos(v)+u.x*sin(v));
}
inline int work(Point u,Point v){
int res=0;
Point w=v-u;
Point a=rotate(w,pi/4),b=rotate(w,-pi/4);
a=a/sqrt(2),b=b/sqrt(2);
Point p1=u+a,p2=u+b;
if(ma.count(point_to_node(p1)))
res+=ma.find(point_to_node(p1))->second;
if(ma.count(point_to_node(p2)))
res+=ma.find(point_to_node(p2))->second;
return res;
}
signed main(){
// freopen("triangle.in","r",stdin);
// freopen("triangle.out","w",stdout);
n=in;
for(int i=1;i<=n;i++){
p[i].x=in,p[i].y=in;
if(!ma.count(point_to_node(p[i]))) ma[point_to_node(p[i])]=1;
else ma[point_to_node(p[i])]++;
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
ans+=work(p[i],p[j]);
printf("%lld\n",ans);
return 0;
}