HDU 5839 Special Tetrahedron(计算几何)

本文介绍了一种算法,用于计算由给定点集中能够组成的至少有四条边相等的四面体的数量,并讨论了如何避免重复计数及特殊情况处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值