HDU 5839 Special Tetrahedron (三维计算几何)

Special Tetrahedron

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 416    Accepted Submission(s): 177

Problem 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,1T20 , the number of test cases.
Each case begins with an integer n(n200) , indicating the number of the points.
The next n lines contains three integers xi,yi,zi , (2000xi,yi,zi2000) , 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
Author
UESTC
Source


题意:给你三维的点,问你有多少个四面体满足以下条件:
1, 至少4条边相等。
2,有4条边相等时,另两条边一定不相邻(即对边).

题解:
n^4暴力,但实际上复杂度达不到n^4,只有n^3*logn。
暴力枚举两个点,然后再枚举距离这两点距离相同的第三个点。
再枚举四个点,找到这个四边形四边相同,但是不共面的四个点。
再判断这个是不是正四边形!
如果是正四边形的话,即六条边都相等,因为你每个边都会作一次当前边,所以会重复计算6次。
如果你的不是正四边形,即4条或5条边相等,因为当前边和对边互换了,所以重复计算2次。

AC代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include <utility>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mst(a) memset(a, 0, sizeof(a))
#define M_P(x,y) make_pair(x,y)  
#define rep(i,j,k) for (int i = j; i <= k; i++)  
#define per(i,j,k) for (int i = j; i >= k; i--)  
#define lson x << 1, l, mid  
#define rson x << 1 | 1, mid + 1, r  
#define LL long long
const int lowbit(int x) { return x&-x; }  
const double eps = 1e-8;  
const int INF = 1e9+7; 
const ll inf =(1LL<<62) ;
const int MOD = 1e9 + 7;  
const int mod = 1000000007;
const int N = 2010; 
const int M=100010; 
template <class T1, class T2>inline void getmax(T1 &a, T2 b) {if (b>a)a = b;}  
template <class T1, class T2>inline void getmin(T1 &a, T2 b) {if (b<a)a = b;}
int read()
{
	int v = 0, f = 1;
	char c =getchar();
	while( c < 48 || 57 < c ){
		if(c=='-') f = -1;
		c = getchar();
	}
	while(48 <= c && c <= 57) 
		v = v*10+c-48, c = getchar();
	return v*f;
}

struct Point{
    int x, y, z;
    Point() {}
    Point(int xx, int yy, int zz):x(xx), y(yy), z(zz){}
}p[210];
 
struct node {
    int d, u;
    node(){}
    node(int dd, int uu):d(dd), u(uu){}
}nd[210];
//求距离 
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.y*v.z - v.y*u.z;
    ret.y = u.z*v.x - u.x*v.z;
    ret.z = u.x*v.y - u.y*v.x;
    return ret;
}

//点积 
int dmul(Point u, Point v) {
    return u.x*v.x + u.y*v.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 onplane(Point a, Point b, Point c, Point d) {
    return  dmul(pvec(a,b,c),subt(d,a)) == 0;
}


int len;
int main()
{
	#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    int t,n;
	int cas=1;
    t=read();
    while(t--)
    {
        n=read();
        for(int i=0; i<n; i++)
            scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
        int ans1 = 0; //6条边不全相等 
        int ans2 = 0; //6条边全相等 
        //枚举点 
        for(int i=0; i<n; i++)
		{
            for(int j=i+1; j<n; j++)
			{  
                len = 0; 
            //枚举到线段ij上距离相等的第三点
                for(int k=0; k<n; k++)
				{
                    if (k == i || k == j) continue;
                    if(Distance(p[i], p[k])  == Distance(p[j], p[k]))
                    {
                    	nd[len++] =node(Distance(p[i], p[k]), k);
					}
			    }
			    
				 	for(int k1 = 0; k1 <len; k1++)
               		{
                    	for (int k2 = k1 + 1; k2 < len; k2++)
                    	{
                        	if (nd[k1].d != nd[k2].d) continue;
                       		if (onplane(p[i], p[j], p[nd[k1].u], p[nd[k2].u])) continue;
                        	if (Distance(p[nd[k1].u], p[nd[k2].u]) == Distance(p[i], p[j]) && Distance(p[nd[k1].u], p[nd[k2].u]) == nd[k1].d)
                            	ans2++; 
                        	else ans1++;
                       }	
                	} 
            }
        } 
        printf("Case #%d: %d\n", cas++, ans1/2+ans2/6);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值