HDU 5839 Special Tetrahedron (计算几何)

Special Tetrahedron

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5839

Description

Given n points which are in three-dimensional space(without repetition). Please find out how many distinct Special Tetrahedron among them. A tetrahedron is called Special Tetrahedron if it has two following characters. 1. At least four edges have the same length. 2. If it has exactly four edges of the same length, the other two edges are not adjacent.

Input

Intput contains multiple test cases. The first line is an integer T,1≤T≤20, the number of test cases. Each case begins with an integer n(n≤200), indicating the number of the points. The next n lines contains three integers xi,yi,zi, (−2000≤xi,yi,zi≤2000), representing the coordinates of the ith point.

Output

For each test case,output a line which contains"Case #x: y",x represents the xth test(starting from one),y is the number of Special Tetrahedron.

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

Source

2016中国大学生程序设计竞赛 - 网络选拔赛
##题意: 在三维空间中给出N个点,找有多少个满足条件的四面体. 1. 四面体至少有四条边相等 2. 若恰好四条边相等,那么剩下的两边不相邻.
##题解: 四面体中每条边仅有一条边与它不相邻, 可以转化一下题目的条件: 寻找四边相等的空间四边形(不能四点共面). 首先枚举该空间四边形中的一条对角线,再计算剩余的点跟这条对角线两端点的距离. 若某点与这对角线两端点的距离相等, 则添加到一个集合中. 枚举集合中的任意两点,与对角线两端点组成一个四边形. 判断该四边形是否符合条件: 首先集合中两点到对角线端点的距离要相等. 其次,这四点要不共面.
在上述判断过程中会出现重复计数: 由于每个四边形有两条对角线,所以在枚举对角形计数时,每个四边形都被计数了两次. 特殊的:如果一个四面体是正四面体,那么这四个点被计数了6次. (每条边都计数一次) 所以在处理过程中要记录出现了几次正四面体. 每当枚举到一个合法的空间四面体时,求一下剩下两条边是否跟其它边相等. 如果相等则计数. 令rep为上述计数次数, rep/6 为正四面体的个数(每个正四面体会计数6次). 根据上述分析, ans/2 - 2*rep/6 即为最后结果.
关于时间复杂度: 上述过程看起来是 O(N^4). 而实际上,每次枚举对角线时,符合条件的点一定在这条对角线的中垂面上. 所以不可能每次枚举对角线时,都有很多点在中垂面上. 所以均摊复杂度并不高.

##代码: ``` cpp #include #include #include #include #include #include #include #include #include #include #include #define LL long long #define double long long #define eps 1e-8 #define maxn 1010 #define mod 1000000007 #define inf 0x3f3f3f3f #define mid(a,b) ((a+b)>>1) #define IN freopen("in.txt","r",stdin); using namespace std;

int n;
struct Point{
double x,y,z;
Point(){}
Point(double tx,double ty) {x=tx;y=ty;}
}p[220];

double Distance(Point p1,Point p2)
{
return ((p1.x-p2.x)(p1.x-p2.x)+(p1.y-p2.y)(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z));
}

Point xmul(Point u, Point v) {
Point ret;
ret.x = u.yv.z - v.yu.z;
ret.y = u.zv.x - u.xv.z;
ret.z = u.xv.y - u.yv.x;
return ret;
}

LL dmul(Point u, Point v) {
return u.xv.x + u.yv.y + u.z*v.z;
}

Point subt(Point u, Point v) {
Point ret;
ret.x = u.x - v.x;
ret.y = u.y - v.y;
ret.z = u.z - v.z;
return ret;
}
/求平面的垂向量/
Point pvec(Point s1, Point s2, Point s3) {
return xmul(subt(s1,s2),subt(s2,s3));
}

/判断四点共面/
bool is_ok(Point a, Point b, Point c, Point d) {
return (dmul(pvec(a,b,c),subt(d,a))) == 0LL;
}

struct node {
int id;
LL dis;
node(){}
node(int tx,LL ty) {id=tx;dis=ty;}
};
vector q;

int main(int argc, char const *argv[])
{
//IN;

int t, ca=1; cin >> t;
while(t--)
{
    scanf("%d", &n);
    for(int i=1; i<=n; i++)
        scanf("%lld %lld %lld", &p[i].x, &p[i].y, &p[i].z);

    int ans = 0;
    int rep = 0;
    for(int i=1; i<=n; i++) {
        for(int j=i+1; j<=n; j++) {  /*枚举对角线*/
            q.clear();
            for(int k=1; k<=n; k++) {
                if(Distance(p[k],p[i]) == Distance(p[k],p[j])) {
                    q.push_back(node(k, Distance(p[k],p[j])));
                }
            }

            int sz = q.size();
            for(int ii=0; ii<sz; ii++) {
                for(int jj=ii+1; jj<sz; jj++) {
                    if(q[ii].dis != q[jj].dis) continue;
                    if(is_ok(p[i],p[j],p[q[ii].id],p[q[jj].id])) continue;  /*四点共面*/
                    ans++;

                    /*是否是正四面体*/
                    if(Distance(p[i],p[j])==q[ii].dis && q[ii].dis==Distance(p[q[ii].id],p[q[jj].id]))
                        rep++;
                }
            }
        }
    }

    ans /= 2;
    ans -= 2*rep/6;

    printf("Case #%d: %d\n", ca++, ans);
}

return 0;

}

posted @ 2016-08-14 17:11  Sunshine_tcf  阅读(1342)  评论(3编辑  收藏  举报