一道普通的hash

题目大意:

有N个点,每加一个点,能组成多少个矩形。

4<=N<=1000,每个点横纵坐标的绝对值不会超过16000

大致思路:

由矩阵的性质得,当一个四边形为矩形时,它的两条对角线相等且平分。

那么不妨设有两条线段,端点坐标分别为(x1,y1)、(x2,y2) 和 (x3,y3)、(x4,y4),那么需要满足:

// 保证平分

1.x1+x2=x3+x4 

2.y1+y2=y3+y4 

// 保证相等

3.(x2-x1)^2+(y2-y1)^2=(x3-x4)^2,(x4-y4)^2 // 因为任何数的平方都是正数,所以就不需要abs了

我们可以假设这两条线段就是某个四边形的对角线,那么只要这两条对角线相等且平分,那么就能确定一个矩形的存在.

所以我们只需要记录每条线段的横坐标之和,纵坐标之和及两端点距离的平方,然后通过hash来判断多少条线段的横坐标之和、纵坐标之和、两端点距离的平方相等并记录答案即可。

解题步骤:

1.读入并存储每个点,让这个点与之前的所有点构成线段.

2.hash判断之前有没有和这条线段的横坐标之和、纵坐标之和、两端点距离的平方相等的线段.

3.如果有,则记录答案;如果没有,则进行标记。

代码:

#include
#include
using namespace std;

const int Mod=3000017;
int n,x[100010],y[100010],h[Mod+10],ans=0,edge=0,num[Mod+10];

int read() {
	int S=0,F=1;char C=getchar();
	for(;C<'0' || C>'9';C=getchar()) if(C=='-') F=-1;
	for(;C>='0' && C<='9';C=getchar()) S=(S<<3)+(S<<1)+C-48;
	return S*F;
}

int main() {
    n=read();
    for(int i=1;i<=n;i++) {
    	x[i]=read(),y[i]=read();
    	for(int j=1;j

由于我的hash不够强大,所以只要强一点的数据就过不了了,所以我们需要进一步来强化hash。

hash:

1.map

map适用于字符串hash,然而这题不是字符串hash...所以过

2.双重hash

即在时间和空间优秀的情况下,进行两次及以上次数的hash。

3.存储被hash值

我们可以将被hash的值存储起来,如果原先hash的值不一样的话,就将它换一个模数。例如本题:

我们可以把不重复的每条线段的横坐标之和,纵坐标之和及两端点距离的平方记录下来。

然后每得到一个hash数就对其进行操作。

所以改进之后代码如下:

#include
using namespace std;

const int Mod=3000017;
int n,x[100010],y[100010],h[Mod+10],xx[Mod+10],yy[Mod+10],l[Mod+10],num[Mod+10],ans=0,edge=0;

int read() {
	int S=0,F=1;char C=getchar();
	for(;C<'0' || C>'9';C=getchar()) if(C=='-') F=-1;
	for(;C>='0' && C<='9';C=getchar()) S=(S<<3)+(S<<1)+C-48;
	return S*F;
}

int main() {
    n=read();
    for(int i=1;i<=n;i++) {
    	x[i]=read(),y[i]=read();
    	for(int j=1;j

 

4.long long自然溢出

将被hash数乘一个很大的数,让它爆unsigned long long的范围,然后它就会溢出,成为一个值。这个值就可以当做为hash值。

5.未完待续...

你可能感兴趣的:(一道普通的hash)