2016中国大学生程序设计竞赛 - 网络选拔赛 hdu 5839 Special Tetrahedron

来源:互联网 发布:js getparameter 编辑:程序博客网 时间:2024/06/01 21:51

题目大意:空间中有n个点,选出四个点构成一个四面体,四面体满足
1、至少四条边相等
2、如果四条边相等,不相等的两条边不相邻
解题思路:
1)先枚举两个点P1,P2。构造一个以这两点为法向量,且经过这条线段中点m1的平面。(空间平面方程:平面法向量为 n=A,B,C,平面方程就为Ax+By+Cz=d)。
2)判断在此平面中的点,记录下来。在这些点中枚举两个点P3,P4。满足,这两个点的中点与P1P2中点的连线垂直P3,P4的连线。这样可以保证至少有四条边相等且不相邻。(两个全等的等腰三角形构成的四面体)。
3)去重。画一下可以发现,六条边相同这个四面体被重复统计了六次。非六条边相等,被重复统计了两次。
注意:在判断六条边是否相等,除了判断P1,P2长度和P3,P4长度是否相等外,还要判断是否和另外相等的四条边是否相等。
比较两个中点坐标,看是否能构成四面体。
精度也要开到位。
此题的测试数据没有重复点,所以也不需要进行去重。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#include<map>#include<vector>#define eps 1e-9using namespace std;typedef long long ll;ll eq,neq;/// 统计六条边相等和非六条边相同的情况ll ans;int n;struct node{    double x,y,z;}p[500];bool cmp(node a,node b){    if(fabs(a.x-b.x)<=eps)    {        if(fabs(a.y-b.y)<=eps)            return a.z<b.z;        return a.y<b.y;    }    return a.x<b.x;}double dis(node a,node b){    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z);}void work(node a,node b){    int getin[300];    int cnt=0;    double dis1=dis(a,b);/// P1,P2两点之间的距离    double dis2,dis3;    node mid;    mid.x=(a.x+b.x)/2;    mid.y=(a.y+b.y)/2,mid.z=(a.z+b.z)/2;/// P1,P2的中点坐标    double k1,k2,k3,d;    k1=a.x-b.x,k2=a.y-b.y,k3=a.z-b.z;   /// 平面方程    d=k1*mid.x+k2*mid.y+k3*mid.z;    for(int i=0;i<n;i++)    {        if(fabs(k1*p[i].x+k2*p[i].y+k3*p[i].z-d)<=eps)///找出在此平面中的点            getin[cnt++]=i;    }    if(cnt<1)        return ;    node mid2;    double m1,m2,m3;    double l1,l2,l3;    for(int i=0;i<cnt;i++)    {        dis3=dis(a,p[getin[i]]);        for(int j=i+1;j<cnt;j++)        {            mid2.x=(p[getin[i]].x+p[getin[j]].x)/2;            mid2.y=(p[getin[i]].y+p[getin[j]].y)/2;            mid2.z=(p[getin[i]].z+p[getin[j]].z)/2;     ///P3,P4的中点坐标            if((fabs(mid.x-mid2.x)<=eps)&&(fabs(mid.y-mid2.y)<=eps)&&(fabs(mid.z-mid2.z)<=eps))///中点相同构不成四面体                continue;            m1=mid2.x-mid.x;m2=mid2.y-mid.y;m3=mid2.z-mid.z;            l1=p[getin[i]].x-p[getin[j]].x;            l2=p[getin[i]].y-p[getin[j]].y;            l3=p[getin[i]].z-p[getin[j]].z;            if(fabs(m1*l1+m2*l2+m3*l3)<=eps) /// 判断几条边相同            {                dis2=dis(p[getin[i]],p[getin[j]]);                if(fabs((dis1-dis2))<=eps&&fabs(dis1-dis3)<=eps)                    eq++;                else neq++;            }        }    }}int main(){    int cas=0;    int T;    scanf("%d",&T);    while(T--)    {        ans=0;        eq=0,neq=0;        scanf("%d",&n);        for(int i=0;i<n;i++)        {            scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);        }        ///=======================================查重,不影响结果,可不加        sort(p,p+n,cmp);        int nn=1;        for(int i=1;i<n;i++)        {            if((fabs(p[i].x-p[i-1].x)<=eps)&&(fabs(p[i].y-p[i-1].y)<=eps)&&(fabs(p[i].z-p[i-1].z)<=eps))                continue;            else            {                p[nn].x=p[i].x;                p[nn].y=p[i].y;                p[nn].z=p[i].z;                nn++;            }        }        n=nn;        ///=================================================        if(n<4)        {            printf("Case #%d: 0\n",++cas);            continue;        }        for(int i=0;i<n;i++)        {            for(int j=i+1;j<n;j++)///枚举P1,P2            {                work(p[i],p[j]);            }        }        ans=eq/6+neq/2;        printf("Case #%d: %I64d\n",++cas,ans);    }    return 0;}
0 0
原创粉丝点击