Poj2002 Squares

题意描述:有一堆平面散点集,任取四个点,求能组成正方形的不同组合方式有多少。相同的四个点,不同顺序构成的正方形视为同一正方形。

思路变迁

1、最简单的方法,直接暴力搜索,即依次取四个顶点,根据其坐标判断是否能组成正方形。组成正方形的条件是四个顶点可组成的六条边里面,有四条相等,剩下两条相等。当然由于其时间复杂度为O(n^4),所以提交结果为TLE

2、考虑降低时间复杂度。如任取三个顶点,根据组成正方形的条件计算得到第四个顶点,判断其是否在点的集合内,其复杂度为O(n^3)。或者任取两个顶点,根据组成正方形的条件计算出另外两个顶点,再判断其是否在点的集合内,其复杂度为O(n^2)。

3、不论是任取两个顶点还是任取三个顶点,其关键一步都是判断计算得到的新的点,是否在点的集合内,基本方法有对点排序再二分查找,或者是使用hash表。我的设计是考虑点所处象限的二维hash表。根据这道题的提交结果来看,所用时间上,堆排序优于快排

4、对于任选两个顶点时,可能存在三种不同的正方形。但是在对所有顶点排序后,如若按序来去顶点,则可发现我们只需始终计算一个方向的即可,且计算结果中同一个正方形重复了两次,所以最终结果除以二。如若不排序直接任取两个的顶点的话,始终按一个方向计算,可以发现每个正方形的四条边,每一条边都会贡献一次得到的正方形的个数,所以最终结果需要除以四

5、在使用hash表后时间复杂度达到最优,即O(nlgn) + hash表平均冲突*n(n-1)/2,所以本问题的进一步优化,取决于怎么更大程度的降低hash表的冲突?考虑位运算,来存储所有的点,但需要空间太大,因为共有40000*40000个点

暴力搜索代码

 1 #include<stdio.h>

 2 #define SIZE 1005

 3 typedef struct POINT {

 4     int x;

 5     int y;

 6 } point;

 7 int isSquare(int a, int b, int c, int d);

 8 point p[SIZE];

 9 int main() {

10     int n, result;

11     int i, j, k, x;

12     scanf("%d", &n);

13     while(n != 0) {

14         result = 0;

15         for(i=1; i<=n; i++)

16             scanf("%d %d", &p[i].x, &p[i].y);

17         for(i=1; i<=n; i++) {

18             for(j=i+1; j<=n; j++) {

19                 for(k=j+1; k<=n; k++) {

20                     for(x=k+1; x<=n; x++) {

21                         if(isSquare(i, j, k, x))

22                             result++;

23                     }

24                 }

25             }

26         }

27         printf("%d\n", result);

28         scanf("%d", &n);

29     }

30 }

31 

32 int isSquare(int a, int b, int c, int d) {

33     int s[6];

34     int num1 = 1, num2 = 1;

35     int side1 = -1, side2 = -1;

36     int i;

37     s[0] = (p[a].x - p[b].x)*(p[a].x - p[b].x) + (p[a].y - p[b].y)*(p[a].y - p[b].y);

38     s[1] = (p[a].x - p[c].x)*(p[a].x - p[c].x) + (p[a].y - p[c].y)*(p[a].y - p[c].y);

39     s[2] = (p[a].x - p[d].x)*(p[a].x - p[d].x) + (p[a].y - p[d].y)*(p[a].y - p[d].y);

40     s[3] = (p[b].x - p[c].x)*(p[b].x - p[c].x) + (p[b].y - p[c].y)*(p[b].y - p[c].y);

41     s[4] = (p[b].x - p[d].x)*(p[b].x - p[d].x) + (p[b].y - p[d].y)*(p[b].y - p[d].y);

42     s[5] = (p[c].x - p[d].x)*(p[c].x - p[d].x) + (p[c].y - p[d].y)*(p[c].y - p[d].y);

43     for(i=0; i<=5; i++) {

44         if(i == 0) {

45             side1 = s[i];

46         }

47         else if(s[i] != side1) {

48             if(side2 == -1)

49                 side2 = s[i];

50             else if(s[i] == side2)

51                 num2++;

52             else

53                 break;

54         }

55         else if(s[i] == side1)

56             num1++;

57     }

58     if((num1==2 && num2==4) || (num1==4 && num2 == 2))

59         return 1;

60     else

61         return 0;

62 }

使用堆排序+二分查找代码

 1 #include<stdio.h>

 2 #define SIZE 1005

 3 typedef struct POiNT {

 4     int x;

 5     int y;

 6 } point;

 7 int cmp(point pa, point pb);

 8 void heapSort(int n);

 9 int binarySearch(int low, int high, point key);

10 void shiftDown(int i, int n);

11 void swap(int i, int j);

12 point p[SIZE];

13 int main() {

14     int n, result;

15     int i, j, k, x;

16     point pa, pb;

17     scanf("%d", &n);

18     while(n != 0) {

19         result = 0;

20         for(i=1; i<=n; i++)

21             scanf("%d %d", &p[i].x, &p[i].y);

22         heapSort(n);

23         for(i=1; i<=n; i++)

24             printf("%d %d\n", p[i].x, p[i].y);

25 

26         for(i=1; i<=n; i++) {

27             for(j=i+1; j<=n; j++) {

28                 pa.x = p[i].x - (p[j].y - p[i].y);

29                 pa.y = p[i].y + (p[j].x - p[i].x);

30                 pb.x = pa.x + (p[j].x - p[i].x);

31                 pb.y = pa.y + (p[j].y - p[i].y);

32                 if(binarySearch(1, n, pa) && binarySearch(1, n, pb))

33                     result++;

34             }

35         }

36         printf("%d\n", result/2);

37         scanf("%d", &n);

38     }

39 }

40 int binarySearch(int low, int high, point key) {

41     int mid = (low + high)/2;

42     if(low > high)

43         return 0;

44     if(cmp(p[mid], key) == 0)

45         return 1;

46     else if(cmp(p[mid], key) == 1)

47         return binarySearch(low, mid-1, key);

48     else

49         return binarySearch(mid+1, high, key);

50 }

51 void heapSort(int n) {

52     int i = n/2;

53     for(; i>0; --i)

54         shiftDown(i, n);

55     for(i=n; i>1;) {

56         swap(1, i);

57         shiftDown(1, --i);

58     }

59 }

60 void shiftDown(int i, int n) {

61     int j = 2*i;

62     for(; j<=n; j=2*i) {

63         if(j < n && cmp(p[j], p[j+1]) == -1)

64             j = j + 1;

65         if(cmp(p[i], p[j]) == -1) {

66             swap(i, j);

67             i = j;

68         } else

69             break;

70     }

71 }

72 void swap(int i, int j) {

73     point temp = p[i];

74     p[i] = p[j];

75     p[j] = temp;

76 }

77 int cmp(point pa, point pb) {

78     if(pa.x > pb.x)

79         return 1;

80     else if(pa.x == pb.x && pa.y > pb.y)

81         return 1;

82     else if(pa.x == pb.x && pa.y == pb.y)

83         return 0;

84     else

85         return -1;

86 }

考虑象限的hash代码

 1 #include<stdio.h>

 2 #include<stdlib.h>

 3 #include<string.h>

 4 #define SIZE 1013

 5 typedef struct POiNT {

 6     int x;

 7     int y;

 8 } point;

 9 struct hashNode {

10     point poi;

11     struct hashNode *next;

12 };

13 int cmp(const void *a, const void *b );

14 void add(point key);

15 int find(point);

16 point p[SIZE];

17 struct hashNode hashTable[5][SIZE];

18 int main() {

19     int n, result;

20     int i, j, k, x;

21     point pa, pb;

22     scanf("%d", &n);

23     while(n != 0) {

24         result = 0;

25         memset(hashTable, 0, sizeof(hashTable));

26         for(i=1; i<=n; i++) {

27             scanf("%d %d", &p[i].x, &p[i].y);

28             add(p[i]);

29         }

30         qsort(p+1, n, sizeof(p[0]), cmp);

31         for(i=1; i<=n; i++) {

32             for(j=i+1; j<=n; j++) {

33                 pa.x = p[i].x - (p[j].y - p[i].y);

34                 pa.y = p[i].y + (p[j].x - p[i].x);

35                 pb.x = pa.x + (p[j].x - p[i].x);

36                 pb.y = pa.y + (p[j].y - p[i].y);

37                 if(find(pa) && find(pb))

38                     result++;

39             }

40         }

41         printf("%d\n", result/2);

42         scanf("%d", &n);

43     }

44 }

45 void add(point key) {

46     int t, num;

47     struct hashNode *newNode;

48     if(key.x >= 0 && key.y >= 0)

49         t = 1;

50     else if(key.x >= 0 && key.y < 0)

51         t = 2;

52     else if(key.x < 0 && key.y < 0)

53         t = 3;

54     else

55         t = 4;

56     num = (key.x*key.x + key.y*key.y)%SIZE;

57     newNode = (struct hashNode*)malloc(sizeof(struct hashNode));

58     newNode->poi = key;

59     newNode->next = hashTable[t][num].next;

60     hashTable[t][num].next = newNode;

61 }

62 int find(point key) {

63     int t, num;

64     struct hashNode *node;

65     if(key.x >= 0 && key.y >= 0)

66         t = 1;

67     else if(key.x >= 0 && key.y < 0)

68         t = 2;

69     else if(key.x < 0 && key.y < 0)

70         t = 3;

71     else

72         t = 4;

73     num = (key.x*key.x + key.y*key.y)%SIZE;

74     node = hashTable[t][num].next;

75     while(node) {

76         if(node->poi.x == key.x && node->poi.y == key.y)

77             return 1;

78         node = node->next;

79     }

80     return 0;

81 }

82 int cmp(const void *a, const void *b )

83 {

84    point c = *(point*)a;

85    point d = *(point*)b;

86 

87     if(c.x == d.x)

88         return c.y - d.y;

89     else

90         return c.x - d.x;

91 }

 

你可能感兴趣的:(poj)