POJ2002-Squares-hash+枚举+几何

http://poj.org/problem?id=2002

给出n个坐标,让你求出 这n个坐标里包含有多少个正方形,n《1000


思路:

直接枚举四个点显然TLE,我们可以枚举2个点作为一对顶点点,以公式计算出另外两个点的坐标(逆时针下),

然后我们在 输入的所有点里面查找,看这2个点是否存在 。存在正方形个数+1


真是数学弱到渣。。。。已知一对顶点,计算正方形另外两个点坐标的时候用几何公式。。double再算。。。一直开始一直TLE、、、后来才发现都是int就够了。。。

   int xx=tm[i].x+tm[j].x+tm[i].y-tm[j].y;

   int yy=tm[i].y+tm[j].y+tm[j].x-tm[i].x;

    由点i,j作为对角线顶点 ,i点逆时针旋转90度后得到的一个点的坐标应该为(xx/2,yy/2)   (不推了。。)

那么判断xx%2  &&yy%2 ,因为题目输入都是int,所以如果答案非整型直接continue;


查找在这用hash,  开放定址法的 二次探测再散列法 解决冲突问题


由于每个正方形会被枚举四次,所以ans 要除四 


---------------经过上面处理, 最快只能跑 1.6S.....

后来看到别人blog发现一个地方可以剪枝。。。

即在枚举顶点时 加上判断 if(tm[j].x >=tm[i].x && tm[i].y-tm[j].y<0)  

这样就能保证 一个正方形只被枚举一次。。 直接卡掉了3/4的无效操作,到了610ms


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
typedef unsigned __int64 ull; 
const double pi=acos(-1.0);
double eps=0.000001;
int n;
int  HASH[200007+5];
const ull mod= 200007    ;  
struct POINT
{
	int x;
	int y;
	POINT(int a=0, int b=0) { x=a; y=b;}
	bool operator <(const  POINT&bb)
	{
		if (x!=bb.x)
			return x<bb.x;
		else
			return y<bb.y;
	}	
	bool operator ==(const  POINT& bb)
	{ 
		if ( x==bb.x && y==bb.y)
			return true;
		else
			return false;
	}
	
};
POINT tm[1005];
int find(int xx,int yy)
{
			ull tt1=xx*239+ yy *113;
				int dd=tt1%mod;  
				int tmp=dd,t=1;
				int flag=0;
				while(HASH[tmp]!=0)  
				{  
				  if ( tm[HASH[tmp]].x==xx&&tm[HASH[tmp]].y==yy)   
				  {flag=1;break;}  
				  tmp=(dd+t*t)%mod;  
				  t++;  
			    }  
				if (!flag) return 0;
				else return 1;
} 
int main()
{ 
 
	while(scanf("%d",&n)!=EOF)
	{
		if (!n) break;
		memset(HASH,0,sizeof(HASH));
		int i,j,tx,ty;
		for (i=1;i<=n;i++)
		{ 
			scanf("%d %d",&tx,&ty); 
			tm[i].x=tx;
			tm[i].y=ty;
			ull tmppppp=tx*239+ty*113;
			int dd=tmppppp%mod;  
			int tmp=dd,t=1;   
        while(HASH[tmp]!=0)  
        {      
            tmp=(dd+t*t)%mod;  
            t++;  
        }  
		 HASH[tmp]=i;  

	 
		}
	  	int ans=0;
		
		for (i=1;i<=n;i++)
		{
			for (j=1;j<=n;j++)
			{
				if (i==j) continue;
		  	if(tm[j].x >=tm[i].x && tm[i].y-tm[j].y<0)  
				{
			    int xx=tm[i].x+tm[j].x+tm[i].y-tm[j].y;
				int yy=tm[i].y+tm[j].y+tm[j].x-tm[i].x;
			if (xx%2 ||yy%2) continue;
			xx/=2;
			yy/=2;
			if (	find(xx,yy)==0 )
				continue;	 
				 xx=tm[i].x+tm[j].x+tm[j].y-tm[i].y;
				 yy=tm[i].y+tm[j].y+tm[i].x-tm[j].x;
			if (xx%2 ||yy%2) continue;
				xx/=2;
			yy/=2;
			if (	find(xx,yy)==0)  continue;
			  	ans++;
				} 
			}
		}
		printf("%d\n",ans);
		 
	}
	return 0;
	
}




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值