HDU 2017 多校联合训练赛2 1011 6055 Regular polygon map&pair

Regular polygon

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


Problem Description
On a two-dimensional plane, give you n integer points. Your task is to figure out how many different regular polygon these points can make.
 

Input
The input file consists of several test cases. Each case the first line is a numbers N (N <= 500). The next N lines ,each line contain two number Xi and Yi(-100 <= xi,yi <= 100), means the points’ position.(the data assures no two points share the same position.)
 

Output
For each case, output a number means how many different regular polygon these points can make.
 

Sample Input
  
  
4 0 0 0 1 1 0 1 1 6 0 0 0 1 1 0 1 1 2 0 2 1
 

Sample Output
  
  
1 2
 

Source
2017 Multi-University Training Contest - Team 2


题目大意
在一个平面直角坐标系中,给出n个点,问这n个点能组成多少个正多边形。(注意:每个点的坐标都是整数)


题目解析
该题目的突破点在于一条性质:如果在平面直角坐标系中,每个点的坐标都是整数,那么这些点能组成的正多边形只能是正方形。(具体证明可参考杨景钦在2017的国家队论文)
在这里我们只是简单理解一下该性质。如果给每种正多边形做外接圆,我们会发现,正多边形的每个点都在它的外接圆上。现在,在坐标系中任意画一个圆,我们会发现,在圆上最多只能找到四个整数坐标点,并且一定是正方形的四个点。

现在,题目就简单了许多。我们只需要枚举任意两点,判断包含这两个点的正方形的另两个点的理论位置上,是否真正存在两个点,如果两个点都存在,那么answer++。注意,如果存在一个正方形,那么这个正方形的4条边上的两个点,都满足判断条件,所以answer++重复操作4次。

判断理论点的位置是否真正存在点,为了简化操作的时间复杂度,我们可以采用两种方法:1.引入vis[ ]数组,记录每个点是否出现过;2.使用STL中的map 和 pair,详情请参考代码。
方法二的好处是空间复杂度更低,对于更大的点的数据量的情况也可以应付;并且代码更简洁;
对于方法一,从代码上来讲,似乎更好理解,但是需要我们特别注意的问题是,数组越界。题目中,坐标的范围是[-100,100],然而我们的数组范围是从0开始的,这样就需要我们将所有的坐标加上100,并不影响后来的计算。另外构成正方形的另外两个理论点的坐标也要保证不能越界。


代码1
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

int n, ans;
int x[505], y[505];
bool vis[205][205];

int main()
{
    while (~scanf ("%d",&n))
    {
        ans = 0;
        memset(vis, 0, sizeof(vis));
        for (int i=0; i<n; ++i)
        {
            scanf ("%d %d",&x[i],&y[i]);
            x[i] += 100;
            y[i] += 100;
            vis[x[i]][y[i]] = 1;
        }
        for (int i=0; i<n; ++i)
        {
            for (int j=i+1; j<n; ++j)
            {
                int dx = y[j]-y[i];
                int dy = x[i]-x[j];
                if (x[i]+dx>=0 && x[i]+dx<=200 && y[i]+dy>=0 && y[i]+dy<=200 
                    && x[j]+dx>=0 && x[j]+dx<=200 && y[j]+dy>=0 && y[j]+dy<=200)
                    if (vis[x[i] + dx][y[i] + dy] && vis[x[j] + dx][y[j] + dy])
                        ans ++;
                if (x[i]-dx>=0 && x[i]-dx<=200 && y[i]-dy>=0 && y[i]-dy<=200 
                    && x[j]-dx>=0 && x[j]-dx<=200 && y[j]-dy>=0 && y[j]-dy<=200)
                    if (vis[x[i] - dx][y[i] - dy] && vis[x[j] - dx][y[j] - dy])
                        ans ++;
            }
        }
        printf ("%d\n",ans/4);
    }
    return 0;
}

代码2
#include <cstdio>
#include <iostream>
#include <cstring>
#include <utility>//pair
#include <map>
using namespace std;

int n, ans;
int x[505], y[505];
map < pair <int, int>, bool> M;

int main()
{
    while (~scanf ("%d",&n))
    {
        ans = 0;
        M.clear();
        for (int i=0; i<n; ++i)
        {
            scanf ("%d %d",&x[i],&y[i]);
            M[make_pair(x[i], y[i])] = 1;
        }
        for (int i=0; i<n; ++i)
        {
            for (int j=i+1; j<n; ++j)
            {
                int dx = y[j]-y[i];
                int dy = x[i]-x[j];
                if (M.count(make_pair(x[i] + dx, y[i] + dy)) && M.count(make_pair(x[j] + dx, y[j] + dy)))
                    ans ++;
                if (M.count(make_pair(x[i] - dx, y[i] - dy)) && M.count(make_pair(x[j] - dx, y[j] - dy)))
                    ans ++;
            }
        }
        printf ("%d\n",ans/4);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值