經典好題。函數
題意是要咱們找出全部的正方形。1000點,只有枚舉咯。測試
如圖,若是咱們知道了正方形A,B的座標,即可以推測出C,D兩點的座標。反之,遍歷全部點做爲A,B點,看C,D點是否存在。存在的話正方形數+1。優化
假設A點座標爲(x1,y1),B點座標爲(x2,y2),則根據三角形全等,易知spa
C點座標:( x1+(y2-y1),y1-(x2-x1) )code
D點座標:( x2+(y2-y1),y2-(x2-x1) )htm
固然,若是咱們遍歷任意兩個點,一個正方形將會被計數四次(四條邊)。咱們能夠只判斷斜率>=0的邊,這條邊在正方形的上方(如圖AB邊),這樣不用重複驗證四次了。blog
過程搞清楚了,下面要解決的就是如何判斷C,D點是否存在了。內存
最簡單的辦法,直接使用set。咱們把出現的點加到set裏,判斷時用find函數便可。固然,時效比較差。筆者測試是1000MS+。string
然後,咱們也能夠使用二分查找。hash
固然,最快仍是hash了。hash分爲兩種,開放尋址和鏈式,來解決衝突。在網上搜了不少解題報告,發現你們不少把鏈式叫作開放尋址……百度百科上有說明,你們能夠看一下:http://baike.baidu.com/view/3140124.htm
下面,貼代碼:
開放尋址,POJ測試最快是219MS,125MS級別的代碼不知是如何實現的==
#include <cstdio> #include <cstring> int prime[]={2,3,5,7,11,13,17,19}; int x[1001],y[1001]; int savex[262144],savey[262144]; bool hash[262144]; inline int calHash(int x,int y) { return ((x<<7)^y)&262143; } void insert(int x,int y) { int h=calHash(x,y); int add=prime[(x^y)&7]; while(hash[h] && (savex[h]!=x || savey[h]!=y)) { h+=add; h&=262143; } hash[h]=true; savex[h]=x; savey[h]=y; } bool find(int x,int y) { int h=calHash(x,y); int add=prime[(x^y)&7]; while(hash[h] && (savex[h]!=x || savey[h]!=y)) { h+=add; h&=262143; } if(hash[h] && savex[h]==x && savey[h]==y) return true; return false; } bool calK(int a,int b) { if(x[a]==x[b]) return false; if(y[a]==y[b]) return true; if(((x[a]-x[b])&(1<<31))==((y[a]-y[b])&(1<<31))) return true; return false; } inline int Abs(int n) { return n<0?-n:n; } int main() { // freopen("in.txt","r",stdin); int n; while(~scanf("%d",&n) && n) { memset(hash,0,sizeof(hash)); for(int i=0;i<n;i++) { scanf("%d%d",x+i,y+i); insert(x[i],y[i]); } int count=0; for(int i=0;i<n;i++) for(int k=i+1;k<n;k++) { if(calK(i,k)) { int _y=Abs(y[i]-y[k]); int _x=Abs(x[i]-x[k]); if(find(x[i]+_y,y[i]-_x) && find(x[k]+_y,y[k]-_x)) count++; } } printf("%d\n",count); } }
鏈式,即發現衝突就在當前位置加一個槽。POJ上最快319MS。固然,每次新建的槽並無delete,會形成內存泄露,現實中仍是別這麼幹,或者及時delete吧。
#include <cstdio> #include <cstring> struct Point { int x,y; bool operator<(const Point& cmp) const { return x==cmp.x?y<cmp.y:x<cmp.x; } } point[1010],p,q; struct Hash { int x,y; Hash* next; Hash() { next=0; } } hash[131072]; inline int calHash(int x,int y) { return ((x<<9)^y)&131071; } void insert(int x,int y) { int h=calHash(x,y); Hash* p=&hash[h]; while(p->next) p=p->next; p->x=x; p->y=y; p->next=new Hash(); } bool find(int x,int y) { int h=calHash(x,y); Hash* p=&hash[h]; while(p->next) { if(p->x==x && p->y==y) return true; p=p->next; } return false; } bool calK(Point& a,Point& b) { if(a.x==b.x) return false; if(a.y==b.y) return true; if(((a.x-b.x)&(1<<31))==((a.y-b.y)&(1<<31))) return true; return false; } inline int Abs(int n) { return n<0?-n:n; } int main() { // freopen("in.txt","r",stdin); int n; while(~scanf("%d",&n) && n) { memset(hash,0,sizeof(hash)); for(int i=0;i<n;i++) { scanf("%d%d",&point[i].x,&point[i].y); insert(point[i].x,point[i].y); } int count=0; for(int i=0;i<n;i++) for(int k=i+1;k<n;k++) { if(calK(point[i],point[k])) { int _y=Abs(point[i].y-point[k].y); int _x=Abs(point[i].x-point[k].x); if(find(point[i].x+_y,point[i].y-_x) && find(point[k].x+_y,point[k].y-_x)) count++; } } printf("%d\n",count); } }
最簡單的辦法,set……1360MS
#include <cstdio> #include <cstring> #include <set> using namespace std; struct Point { int x,y; bool operator<(const Point& cmp) const { return x==cmp.x?y<cmp.y:x<cmp.x; } } point[1010],p,q; set<Point> ss; bool calK(Point& a,Point& b) { if(a.x==b.x) return false; if(a.y==b.y) return true; if(((a.x-b.x)&(1<<31))==((a.y-b.y)&(1<<31))) return true; return false; } inline int Abs(int n) { return n<0?-n:n; } int main() { // freopen("in.txt","r",stdin); int n; while(~scanf("%d",&n) && n) { ss.clear(); for(int i=0;i<n;i++) { scanf("%d%d",&point[i].x,&point[i].y); ss.insert(point[i]); } int count=0; for(int i=0;i<n;i++) for(int k=i+1;k<n;k++) { if(calK(point[i],point[k])) { int _y=Abs(point[i].y-point[k].y); int _x=Abs(point[i].x-point[k].x); p.x=point[i].x+_y; p.y=point[i].y-_x; if(ss.find(p)==ss.end()) continue; p.x=point[k].x+_y; p.y=point[k].y-_x; if(ss.find(p)!=ss.end()) count++; } } printf("%d\n",count); } }
三個版本是慢慢優化出來的,哈希函數也有區別。