Description
给出n个整点,先从这n个点中选四个点,问其组成一个至少四条边相等的四面体的方案数,注意如果该四面体只有四条边相等那么另外两条边必须是对边
Input
第一行一整数T表示用例组数,每组用例首先输入一整数n表示点数,之后n行每行三个整数x,y,z表示该点的横纵竖坐标(T<=20,n<=200,-2000<=x,y,z<=2000)
Output
对于每组用例,输出合法方案数
Sample Input
2
4
0 0 0
0 1 1
1 0 1
1 1 0
9
0 0 0
0 0 2
1 1 1
-1 -1 1
1 -1 1
-1 1 1
1 1 0
1 0 1
0 1 1
Sample Output
Case #1: 1
Case #2: 6
Solution
对于一个四边形abcd,首先n^2枚举两点a和b,找到ab中点e之后从剩余n-2个点中找c点使得ce与ab垂直,开一个map存ce距离,对每个距离ce再开一个vector存c点,之后对于每个距离,从中任取两点c和d有ac=ad=bc=bd,但是要去掉两种情况,一种是abcd四点共面的情况,另一种是abcd构成一个正四面体的情况,因为按以上规则统计的话,对于四条边相等或者五条边相等的四面体会被统计两次,而正四面体会被统计六次,所以正四面体的情况要单独拿出来计数
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 222
struct Point
{
ll x,y,z;
Point(){};
Point(ll _x,ll _y,ll _z)
{
x=_x,y=_y,z=_z;
}
Point operator +(const Point &b)const
{
Point c;
c.x=x+b.x,c.y=y+b.y,c.z=z+b.z;
return c;
}
Point operator*(const ll &n)const
{
Point c;
c.x=n*x,c.y=n*y,c.z=n*z;
return c;
}
Point operator/(const ll &n)const
{
Point c;
c.x=x/n,c.y=y/n,c.z=z/n;
return c;
}
void out()
{
printf("x=%I64d y=%I64d z=%I64d\n",x,y,z);
}
}p[maxn];
ll dis(Point a,Point b)//求a,b两点间距
{
ll x=a.x-b.x,y=a.y-b.y,z=a.z-b.z;
return x*x+y*y+z*z;
}
bool check(Point a,Point b,Point c,Point d)//判断ab与cd是否垂直
{
if((a.x-b.x)*(c.x-d.x)+(a.y-b.y)*(c.y-d.y)+(a.z-b.z)*(c.z-d.z)==0)return 1;
return 0;
}
int T,n,Case=1;
map< ll,vector<Point> >m;
map< ll,vector<Point> >::iterator it;
vector<Point>v;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%I64d%I64d%I64d",&p[i].x,&p[i].y,&p[i].z);
p[i]=p[i]*2ll;
}
int ans1=0,ans2=0;
for(int a=1;a<=n;a++)
for(int b=a+1;b<=n;b++)
{
Point t=(p[a]+p[b])/2;
//printf("t:");
//t.out();
m.clear();
for(int c=1;c<=n;c++)
if(c!=a&&c!=b&&check(p[a],p[b],p[c],t))
m[dis(p[c],t)].push_back(p[c]);
for(it=m.begin();it!=m.end();it++)
{
v=it->second;
ll d=it->first,dab=dis(p[a],p[b]);
//printf("d=%I64d:\n",d);
//for(int i=0;i<v.size();i++)v[i].out();
int cnt=v.size();
ans1+=cnt*(cnt-1)/2;
//四点共面情况
for(int i=0;i<cnt;i++)
for(int j=i+1;j<cnt;j++)
if(dis(v[i],v[j])==4ll*d)ans1--;
//正四面体情况
if(4ll*d==3ll*dab)
{
for(int i=0;i<cnt;i++)
for(int j=i+1;j<cnt;j++)
if(dis(v[i],v[j])==dab)
ans1--,ans2++;
}
}
}
printf("Case #%d: %d\n",Case++,ans1/2+ans2/6);
}
return 0;
}