POJ 2002 -- Squares
Time Limit: 3500MS | Memory Limit: 65536K | |
Total Submissions: 20896 | Accepted: 8040 |
Description
A square is a 4-sided polygon whose sides have equal length and adjacent sides form 90-degree angles. It is also a polygon such that rotating about its centre by 90 degrees gives the same polygon. It is not the only polygon with the latter property, however, as a regular octagon also has this property.So we all know what a square looks like, but can we find all possible squares that can be formed from a set of stars in a night sky? To make the problem easier, we will assume that the night sky is a 2-dimensional plane, and each star is specified by its x and y coordinates.
Input
The input consists of a number of test cases. Each test case starts with the integer n (1 <= n <= 1000) indicating the number of points to follow. Each of the next n lines specify the x and y coordinates (two integers) of each point. You may assume that the points are distinct and the magnitudes of the coordinates are less than 20000. The input is terminated when n = 0.Output
For each test case, print on a line the number of squares one can form from the given stars.Sample Input
4
1 0
0 1
1 1
0 0
9
0 0
1 0
2 0
0 2
1 2
2 2
0 1
1 1
2 1
4
-2 5
3 7
0 0
5 2
0
Sample Output
1
6
1
Source
Rocky Mountain 2004題意:
有一堆平面散點集,任取四個點,求能組成正方形的不同組合方式有多少。
相同的四個點,不同順序構成的正方形視為同一正方形。
解題思路:
首先,不可以四個點四個點地枚舉,看他們會不會組成正方形,肯定超時
我們枚舉兩個點,然後通過計算,得到能與他們組成正方形的剩下兩個點的坐標
假設,我們知道了A(x1,y1)和B(x2,y2),那麽通過全等三角形(兩個紅色三角形)的關系(如下圖,請忽視我的渣字和渣圖(..??_??..))
我們可以得到一種情況,
已知:(x1,y1) (x2,y2)
則:
x3=x1-(y1-y2) y3= y1+(x1-x2)
x4=x2-(y1-y2) y4= y2+(x1-x2)
另一種情況就是:
x3=x1+(y1-y2) y3= y1-(x1-x2)
x4=x2+(y1-y2) y4= y2-(x1-x2)
但是註意這種情況,會有重復計算的邊,根據詳細算法內容應作出最後處理
the magnitudes of the coordinates are less than 20000.
坐標的大小小於20000.
1)方法1(超時)
我們先枚舉兩個點,計算兩個點之間的距離,距離%mod作為key值
處理沖突使用鏈地址法
如果遇到key值相同的兩條邊,則有可能會組成正方形,利用公式進行計算,如果組成了正方形,將計數++,將新加入的邊插入Hash
好吧,上述算法很不爭氣的超時了
1 /*超時,待優化*/ 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 int ans; 6 int nodes[10001][2]; 7 const int mod = 20000; 8 class HashTable{ 9 public: 10 int node1,node2;//記錄組成一條邊的兩個點的下標值 11 HashTable *next; 12 HashTable() 13 { 14 next = 0; 15 } 16 }; 17 18 HashTable *Hash[mod]; 19 20 bool isSquare(int x1,int x2,int x3,int x4) 21 { 22 if(nodes[x3][0] == nodes[x1][0]-(nodes[x1][1]-nodes[x2][1])//x3=x1-(y1-y2) 23 && nodes[x3][1] == nodes[x1][1]+(nodes[x1][0]-nodes[x2][0])// y3= y1+(x1-x2) 24 && nodes[x4][0] == nodes[x2][0]-(nodes[x1][1]-nodes[x2][1]) //x4=x2-(y1-y2) 25 && nodes[x4][1] == nodes[x2][1]+(nodes[x1][0]-nodes[x2][0]))//y4= y2+(x1-x2) 26 return true; 27 if(nodes[x3][0] == nodes[x1][0]+(nodes[x1][1]-nodes[x2][1])//x3=x1-(y1-y2) 28 && nodes[x3][1] == nodes[x1][1]-(nodes[x1][0]-nodes[x2][0])// y3= y1+(x1-x2) 29 && nodes[x4][0] == nodes[x2][0]+(nodes[x1][1]-nodes[x2][1]) //x4=x2-(y1-y2) 30 && nodes[x4][1] == nodes[x2][1]-(nodes[x1][0]-nodes[x2][0]))//y4= y2+(x1-x2) 31 return true; 32 if(nodes[x4][0] == nodes[x1][0]-(nodes[x1][1]-nodes[x2][1])//x3=x1-(y1-y2) 33 && nodes[x4][1] == nodes[x1][1]+(nodes[x1][0]-nodes[x2][0])// y3= y1+(x1-x2) 34 && nodes[x3][0] == nodes[x2][0]-(nodes[x1][1]-nodes[x2][1]) //x4=x2-(y1-y2) 35 && nodes[x3][1] == nodes[x2][1]+(nodes[x1][0]-nodes[x2][0]))//y4= y2+(x1-x2) 36 return true; 37 if(nodes[x4][0] == nodes[x1][0]+(nodes[x1][1]-nodes[x2][1])//x3=x1-(y1-y2) 38 && nodes[x4][1] == nodes[x1][1]-(nodes[x1][0]-nodes[x2][0])// y3= y1+(x1-x2) 39 && nodes[x3][0] == nodes[x2][0]+(nodes[x1][1]-nodes[x2][1]) //x4=x2-(y1-y2) 40 && nodes[x3][1] == nodes[x2][1]-(nodes[x1][0]-nodes[x2][0]))//y4= y2+(x1-x2) 41 return true; 42 return false; 43 44 } 45 46 void Insert(int x,int y) 47 { 48 int key = (nodes[x][0] - nodes[y][0])*(nodes[x][0] - nodes[y][0])%mod 49 + (nodes[x][1] - nodes[y][1])*(nodes[x][1] - nodes[y][1])%mod; 50 key = key%mod; 51 if(!Hash[key])//不發生沖突 52 {//直接將邊插入 53 HashTable *temp = new HashTable; 54 temp->node1 = x;temp->node2 = y; 55 Hash[key] = temp; 56 }else{ 57 //發生沖突 58 HashTable *temp = Hash[key]; 59 if(temp->node1 != x && temp->node1 != y 60 && temp->node2 != x && temp->node2 != y 61 && isSquare(temp->node1,temp->node2,x,y))//如果存在相同的點,直接短路。不進入isSquare計算 62 {//構成正方形 63 ans++; 64 } 65 while(temp->next) 66 { 67 temp = temp->next; 68 if(temp->node1 != x && temp->node1 != y 69 && temp->node2 != x && temp->node2 != y 70 && isSquare(temp->node1,temp->node2,x,y)) 71 {//構成正方形 72 ans++; 73 } 74 } 75 temp->next = new HashTable; 76 temp->next->node1 = x; 77 temp->next->node2 = y; 78 } 79 } 80 int main() 81 { 82 int n; 83 while(cin>>n && n != 0) 84 { 85 memset(Hash,0,sizeof(Hash)); 86 ans = 0; 87 for(int i=1;i<=n;i++) 88 { 89 cin>>nodes[i][0]>>nodes[i][1]; 90 } 91 for(int i=1;i<=n-1;i++) 92 for(int j=i+1;j<=n;j++) 93 { 94 if(i == j) continue;//同一個點不能構成邊 95 Insert(i,j);//將第i和j點組成的邊插入Hash 96 } 97 cout<<ans/2<<endl; 98 } 99 return 0; 100 }
看樣這種,先尋找相同長度的邊,再檢查點,查看其是否能組成正方形的方法,會產生太多多余計算。
2)方法二
看到了一篇文章POJ2002-Squares
她的方法是用點(x,y),x*x + y*y來標記點,然後枚舉兩個點,直接從hash表中,查找與這兩個點組成正方形的其余兩個點在hash中是否存在。
那位博主的代碼如下(偷懶ing
1 //Memory Time 2 //652K 1438MS 3 4 #include<iostream> 5 using namespace std; 6 7 const int prime=1999; //長度為2n區間的最大素數 (本題n=1000) 8 9 //其他prime可取值: 10 // 1n 區間: 997 1704ms 11 // 2n 區間: 1999 1438ms 12 // 8n 區間: 7993 1110ms 13 // 10n 區間: 9973 1063ms 14 // 30n 區間: 29989 1000ms 15 // 50n 區間: 49999 1016ms 16 // 100n區間: 99991 1000ms 17 18 //為了盡量達到key與地址的一一映射,hash[]至少為1n, 19 //當為1n時,空間利用率最高,但地址沖突也相對較多,由於經常要為解決沖突開放尋址,使得尋找key值耗時O(1)的情況較少 20 //當n太大時,空間利用率很低,但由於key分布很離散,地址沖突也相對較少,使得尋找鍵值耗時基本為O(1)的情況 21 22 typedef class 23 { 24 public: 25 int x,y; 26 }Node; 27 28 typedef class HashTable 29 { 30 public: 31 int x,y; //標記key值對應的x,y 32 HashTable* next; //當出現地址沖突時,開放尋址 33 34 HashTable() //Initial 35 { 36 next=0; 37 } 38 }Hashtable; 39 40 Node pos[1001]; 41 Hashtable* hash[prime]; //hash[]是指針數組,存放地址 42 43 void insert_vist(int k) 44 { 45 int key=((pos[k].x * pos[k].x)+(pos[k].y * pos[k].y))%prime +1; //+1是避免==0 46 //使key從[0~1998]後移到[1~1999] 47 if(!hash[key]) 48 { 49 Hashtable* temp=new Hashtable; 50 temp->x=pos[k].x; 51 temp->y=pos[k].y; 52 hash[key]=temp; 53 } 54 else //hash[key]已存地址,地址沖突 55 { 56 Hashtable* temp=hash[key]; 57 58 while(temp->next) //開放尋址,直至next為空 59 temp=temp->next; 60 61 temp->next=new HashTable; //申請新結點,用next指向,記錄x、y 62 temp->next->x=pos[k].x; 63 temp->next->y=pos[k].y; 64 } 65 return; 66 } 67 68 bool find(int x,int y) 69 { 70 int key=((x * x)+(y * y))%prime +1; 71 72 if(!hash[key]) //key對應的地址不存在 73 return false; 74 else 75 { 76 Hashtable* temp=hash[key]; 77 78 while(temp) 79 { 80 if(temp->x==x && temp->y==y) 81 return true; 82 83 temp=temp->next; 84 } 85 } 86 87 return false; 88 } 89 90 int main(void) 91 { 92 int n; 93 while(cin>>n) 94 { 95 if(!n) 96 break; 97 98 memset(hash,0,sizeof(hash)); //0 <-> NULL 99 100 for(int k=1;k<=n;k++) 101 { 102 cin>>pos[k].x>>pos[k].y; 103 insert_vist(k); //插入哈希表,標記散點 104 } 105 106 int num=0; //正方形的個數 107 for(int i=1;i<=n-1;i++) 108 for(int j=i+1;j<=n;j++) 109 { 110 int a=pos[j].x-pos[i].x; 111 int b=pos[j].y-pos[i].y; 112 113 int x3=pos[i].x+b; 114 int y3=pos[i].y-a; 115 int x4=pos[j].x+b; 116 int y4=pos[j].y-a; 117 118 if(find(x3,y3) && find(x4,y4)) 119 num++; 120 121 x3=pos[i].x-b; 122 y3=pos[i].y+a; 123 x4=pos[j].x-b; 124 y4=pos[j].y+a; 125 126 if(find(x3,y3) && find(x4,y4)) 127 num++; 128 } 129 130 cout<<num/4<<endl; //同一個正方形枚舉了4次 131 } 132 return 0; 133 }
POJ 2002 -- Squares