Parallelogram Counting
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 6969 | Accepted: 2446 |
Description
There are n distinct points in the plane, given by their integer coordinates. Find the number of parallelograms whose vertices lie on these points. In other words, find the number of 4-element subsets of these points that can be written as {A, B, C, D} such that AB || CD, and BC || AD. No four points are in a straight line.
Input
The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases. It is followed by the input data for each test case.
The first line of each test case contains an integer n (1 <= n <= 1000). Each of the next n lines, contains 2 space-separated integers x and y (the coordinates of a point) with magnitude (absolute value) of no more than 1000000000.
Output
Output should contain t lines.
Line i contains an integer showing the number of the parallelograms as described above for test case i.
Sample Input
2 6 0 0 2 0 4 0 1 1 3 1 5 1 7 -2 -1 8 9 5 7 1 1 4 8 2 0 9 8
Sample Output
5 6
Source
Tehran Sharif 2004 Preliminary
题意:
给你二维平面上n(n<=1e3)个点的坐标,保证没有四线共点,让你求可以组成的平行四边形的个数。
思路:
没有四线共点,言外之意就是有三线共点。(样例也给出了)
确定一个平行四边形,我们可以用多种方法,但是本题的复杂度要求在O(n*n)之内,也就是说我们只能记录每条边的信息,因此我们采用对边平行且相等来确定平行四边形。
我们对于任意两个点,可以求出它们的斜率(不存在设为inf)和距离。
我们显然只能枚举一个条件来判断另一个。
在纸上画画不难发现,在没有四点共线的情况下,n个点的完全图长度相同的边的数量很少。
于是我们把相同长度的边分组,每组暴力找有多少对斜率相同的边即可。
由于我们没有确定找的是平行四边形的上边还是下边,所以最后答案要除以2。
注意内存限制的比较紧,数组开到5e5即可。
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
const int maxn=1005;
const ll mo=1000000007;
const double eps=1e-12;
ll n,m,k;
struct node
{
ll v;
double x;
int id;
bool operator<(node aa) const
{
return v<aa.v;
}
}hs[maxn*maxn>>1];
ll x[maxn],y[maxn];
ll tmp,cnt,ans;
struct nd
{
int a,b;
double xl;
}c[maxn];
ll cc;
ll power(ll a,ll n) //a的n次方mod
{
ll ans=1;
a=a%mo;
while (n)
{
if(n&1) ans=(ans*a)%mo;
n>>=1;
a=(a*a)%mo;
}
return ans;
}
double cal(int i,int j)
{
if(x[i]==x[j]) return inf;
return (double)(y[i]-y[j])/(double)(x[i]-x[j]);
}
ll cal2(int i,int j)
{
return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
cnt=0;
rep(i,1,n)
{
scanf("%lld%lld",&x[i],&y[i]);
rep(j,1,i-1)
{
hs[cnt].v=cal2(i,j);
hs[cnt].x=cal(i,j);
hs[cnt].id=i*n+j;
cnt++;
}
}
sort(hs,hs+cnt);
int ct=0;
ll ans=0;
rep(i,0,cnt-1)
{
if(i==0||hs[i].v!=hs[i-1].v)
{
cc=0;
c[cc].xl=hs[i].x;
c[cc].a=hs[i].id/n;
c[cc].b=hs[i].id%n;
cc++;
}
else
{
c[cc].xl=hs[i].x;
c[cc].a=hs[i].id/n;
c[cc].b=hs[i].id%n;
//cc++;
rep(j,0,cc-1)
if(c[j].xl==c[cc].xl){
if(c[j].a==c[cc].a) continue;
if(c[j].a==c[cc].b) continue;
if(c[j].b==c[cc].a) continue;
if(c[j].b==c[cc].b) continue;
//cout<<c[j].a<<" "<<c[j].b<<" "<<c[cc].a<<" "<<c[cc].b<<" * "<<c[j].xl<<" * "<<c[cc].xl<<endl;
ans++;
}
cc++;
}
}
ans>>=1;
printf("Case %d: %lld\n",cas++,ans);
}
return 0;
}