zoukankan      html  css  js  c++  java
  • POJ 2002 -- Squares

    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

     

    题意:

    有一堆平面散点集,任取四个点,求能组成正方形的不同组合方式有多少。

    相同的四个点,不同顺序构成的正方形视为同一正方形。

    解题思路:

    首先,不可以四个点四个点地枚举,看他们会不会组成正方形,肯定超时

    我们枚举两个点,然后通过计算,得到能与他们组成正方形的剩下两个点的坐标

    假设,我们知道了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 }
  • 相关阅读:
    BlockingQueue(阻塞队列)详解
    支付宝系统架构(内部架构图)
    微博的消息队列
    JVM源码分析之堆外内存完全解读
    滑动冲突的补充——Event的流程走向
    BaseFragment的定义—所有Fragment的父类
    BaseActivity的定义——作为所有Activity类的父类
    BGARefreshLayout-Android-master的简单使用
    分析BGARefreshLayout-master
    简便数据库——ORMLite框架
  • 原文地址:https://www.cnblogs.com/yxh-amysear/p/8443459.html
Copyright © 2011-2022 走看看