20200314 SCOI模拟T3(计算几何)

该博客介绍了如何在二维平面上,给定N个点的情况下,找出能构成等腰直角三角形的组合数。通过枚举斜边并判断直角顶点是否存在,实现O(n^2)的时间复杂度解决方案。博客提到了利用unordered_map存储结构体,并特别强调了不能使用double类型以避免精度问题。
摘要由CSDN通过智能技术生成

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 1n3000,0xi,yi109 。由于坐标都是整数,不存在精度误差问题。

思路:

枚举等腰直角三角形的斜边,每次判断直角顶点存不存在,时间复杂度 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值