洛谷P1665 正方形计数/caioj1211: 统计正方形

题面
这是一道计算几何的入门题
当然,可以用搜索什么的过,但是会慢一点
那么我们来理一理思路
我们枚举每一个可能正方形的对角线
首先我们有这样的一个正方形:

其中黑色的两个点是确定的,我们要得到另外两个红点的坐标……
使用毕达哥拉斯平方定理!使用锐角三角正切函数!求出斜率!暴力代入! 这些方法会损精度的……
我们要用一种挺巧妙的方法:
连原来的两个点,求出中点:

然后从终点向x,y轴各引一条垂线与正方形的边相交
我们很容易就会证到
在这里插入图片描述
图中两个上色的三角形全等。
然后就很容易明白两条蓝线等长了啦QωQ
上面那条蓝线就是中点和另一个点的纵坐标差,
下面那条就是中点和待求点的横坐标差了,
酱紫就可以由中点坐标求到两个红点的纵坐标了嘛!
求横坐标也是如此啦……

然后呢,接下来有两种做法:
第一是用哈希表来找求出来的两个红点有没有出现过
第二是用一个布尔数组来存每个坐标是否有点
当然哈希会省点内存而且能处理带小数的情况
但是我很懒QωQ就用第二种了

还要注意一点!
在枚举时会把原来当过红点的点重新算一遍
所以最终答案要除以二

#include<cstdio>
#include<cstring>
using namespace std;
struct point
{
	int x,y;//为什么不用double呢?因为由全等可以证明:当一个正方形两点都在整数坐标上时,
	//其他两点也会在整点上
}a[510];
bool v[310][310];
int main()
{
	int n;scanf("%d",&n);
	int ans=0;
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i].x,&a[i].y),
		(a[i].x+=51)<<=1,(a[i].y+=51)<<=1,//防止负数,另外还要防止中点出现小数坐标
		v[a[i].x][a[i].y]=1;
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
		{
			int xmid=(a[i].x+a[j].x)>>1,ymid=(a[i].y+a[j].y)>>1;//中点的坐标
			int x1=xmid-(a[i].y-ymid),y1=ymid-(xmid-a[i].x);//这是下面那个点
			int x2=xmid+(a[i].y-ymid),y2=ymid+(xmid-a[i].x);//上面那个点明显就是反过来的啦
			if(0<=x1&&x1<=300&&0<=y1&&y1<=300&&0<=x2&&x2<=300&&0<=y2&&y2<=300)
				if(v[x1][y1]&&v[x2][y2])ans++;
		}
	printf("%d",ans>>1);
	return 0;
}

欢迎在评论区留言提问哦QωQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值