CF660D 平行四边形

1 CF660D 平行四边形

2 题目描述

时间限制 \(4s\) | 空间限制 \(256M\)

给出同一个平面上的 \(n\) 个点,所有的点都分散,没有任何三个点在同一条直线上。找出以这些点为顶点的平行四边形的个数。

3 题解

平行四边形的一个判定就是一组对边平行且相等。我们可以 \(O(n^2)\) 枚举有序的两个节点,计算这两个节点 \((x_i ,y_i)\)\((x_j, y_j)\) 之间的那条线段的斜率和那条线段的长度。斜率就是 \(\frac{x_i - x_j}{y_i - y_j}\),长度就是 \(\sqrt{(x_j - x_i)^2 + (y_j - y_i)^2}\)。然后,我们用 \(map\) 存储这两个元素,如果存在别的线段的两个元素与这个完全相同,那么这四个节点就可以组成一个平行四边形。如果有两个点的纵坐标相同,那么就单独记录一下这些线段的斜率。这里有个小 \(trick\),由于我们用 \(map\) 时并不在意具体的数值,只在意是否相同,所以长度我们可以只记录 \((x_j - x_i)^2 + (y_j - y_i)^2\) 即可,避免丢失精度。

注意:我们对于每一个平行四边形都会从横竖两组边统计两边,所以最后的答案要记得除以 \(2\)

4 代码(空格警告):

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
const int N = 2005;
#define int long long
int n, ans;
struct node
{
    int x, y;
}a[N];
map< pair<int, int>, int > m;
int get(int x1, int y1, int x2, int y2)
{
    return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
}
signed main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i].x >> a[i].y;
    for (int i = 1; i <= n; i++)
    {
        for (int j = i+1; j <= n; j++)
        {
            if (a[i].y - a[j].y == 0) m[make_pair(-1, abs(a[i].x - a[j].x))]++;
            else m[make_pair((a[i].x - a[j].x) * 100000000 / (a[i].y - a[j].y), get(a[i].x, a[i].y, a[j].x, a[j].y))]++;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = i+1; j <= n; j++)
        {
            if (a[i].y - a[j].y == 0)
            {
                m[make_pair(-1, abs(a[i].x - a[j].x))]--;
                ans += m[make_pair(-1, abs(a[i].x - a[j].x))];
            }
            else
            {
                m[make_pair((a[i].x - a[j].x) * 100000000 / (a[i].y - a[j].y), get(a[i].x, a[i].y, a[j].x, a[j].y))]--;
                ans += m[make_pair((a[i].x - a[j].x) * 100000000 / (a[i].y - a[j].y), get(a[i].x, a[i].y, a[j].x, a[j].y))];
            }
        }
    }
    cout << ans / 2;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-21 11:11  David24  阅读(54)  评论(0编辑  收藏  举报