您的位置:首页 > 理论基础 > 计算机网络

hdu 5839(空间几何 网络选拔赛)

2016-08-15 11:06 218 查看
题意:

在三维空间给出若干个点,在这些点中选取四个点,组成四面体,满足这个四面体中至少有四条边是相等的。并且另两条不相等的边必须不相邻。

解题思路:

就是找出两条边,将这两条边作为四面体的对边。枚举第一条边找第二条边。找到一个平面经过第一条边的中点,且与第一条边垂直,第二条直线肯定在次平面内。所以枚举第一条直线的两个点,并且找到上述的平面,再遍历所有的点,找出在此平面上的点。在这些点中任意找两个点判断是否满足条件。满足条件的四面体分两种情况,一种是四条边相等,第二种是六条边相等。五条边相对的与四条边相等的情况一样。分这两种情况因为六条边相等的情况会被重复计算六次,四条边相等的被重复算两次。然后分开统计,之后出一下就是答案了。

(本来赛时是有思想的,结果实现的时候有一些情况忘记判断了,比如刚开始两条直线的重点重合也被统计了)

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#define eps 1e-11
using namespace std;
typedef long long ll;
ll neq,eq;
ll ans;
int n;
struct node
{
double x,y,z;
}p[300];

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 juli(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=juli(a,b);
double dis2;
node mid;///第一条边中点
mid.x=(a.x+b.x)/2;
mid.y=(a.y+b.y)/2,mid.z=(a.z+b.z)/2;
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++)
{
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;
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)
{
if(fabs(m1)<eps&&fabs(m2)<eps&&fabs(m3)<eps)
///当找到的两条直线的中点重合不满足条件
{
continue;
}
dis2=juli(p[getin[i]],p[getin[j]]);
if(fabs((dis1-dis2))<=eps&&fabs(juli(a,p[getin[i]])-juli(a,b))<=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++)///枚举第一条边的两个点
{
work(p[i],p[j]);
}
}
ans=eq/6+neq/2;
printf("Case #%d: %I64d\n",++cas,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息