ACM/ICPC 之 三维计算几何+暴力枚举+判重(HDU5839)

CCPC网赛第八题,求立体几何数量,题解见注释

 

//立体几何-求满足要求的四面体个数
//要求1:至少4条边相等
//要求2:四条边相等时,另两条边一定不相邻(即对边)
//题解:以当前边为不相邻的其中一条边,对可以构成等腰三角形的第三点进行枚举
//再对这些第三点的集合做一次n^2的枚举,分两种情况找出四面体
//如果四条边或五条边相同,则只存在两种重复情况(当前边和对边互换)
//如果六条边相同,则存在六种重复情况(每个边作一次当前边)
//Time:499Ms	Memory:1576K
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

#define MAXP 205
#define POW(x) ((x)*(x))

struct Point{
	int x, y, z;
	Point() {}
	Point(int xx, int yy, int zz):x(xx), y(yy), z(zz){}
}p[MAXP];

struct Node {
	int d, u;
	Node(){}
	Node(int dd, int uu):d(dd), u(uu){}
}nd[MAXP];

int n;
int len;

int Distance(Point a, Point b)
{
	return POW(a.x - b.x) + POW(a.y - b.y) + POW(a.z - b.z);
}

Point xmult(Point a, Point b) //叉积
{
	return Point(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
}
//向量差a-b(b到a)
Point subt(Point a, Point b)
{
	return Point(a.x - b.x, a.y - b.y, a.z - b.z);
}

int dmult(Point a, Point b)	//点积
{
	return a.x*b.x + a.y*b.y + a.z*b.z;
}

//取平面法向量
Point normalv(Point a, Point b, Point c)
{
	return xmult(subt(a, b), subt(b, c));
}

bool onplane(Point a, Point b, Point c, Point d)	//四点共面
{
	return dmult(normalv(a, b, c), subt(d, a)) == 0;
}

int main()
{
	//freopen("t.in", "r", stdin);
	int T;
	int cas = 1;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
			scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
		int sum1 = 0, sum2 = 0;	//sum1:六条边不全相等,sum2:六条边都相等
		for (int i = 0; i < n; i++)
		{
			for (int j = i + 1; j < n; j++)
			{
				len = 0;
				for (int k = 0; k < n; k++)	//枚举到ij线段上距离相等的第三点k
				{
					if (k == i || k == j) continue;
					int tmp = Distance(p[i], p[k]);
					if (tmp == Distance(p[j], p[k]))
						nd[len++] = Node(tmp, 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;
						int tmp = Distance(p[nd[k1].u], p[nd[k2].u]);
						if (tmp == Distance(p[i], p[j])	&& tmp == nd[k1].d)
							sum2++;	//六条边相等
						else sum1++;
					}
				}

			}
		}
		printf("Case #%d: %d\n", cas++, sum1/2+sum2/6);
	}

	return 0;
}

 

posted @ 2016-08-15 01:00  文字失效  阅读(292)  评论(0编辑  收藏  举报