标签:
大神说是水题,可我小白;
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5839
题意:给n个不重且为正数点(范围2000),问满足题意的四个点的组数;
条件1:四个点可以构成一个四面体,并且最少有四个边相等;2:如果仅有四个边相等,不相等的两边不相邻;
想法:四面体有四条边相等,即在相等的边里找符合要求的四点,把三维的点转化为边,边长度排序,即得相等的边在一块线性处理,在相等的边里枚举符合条件的组合数,
并且去重,即得答案。
代码:
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> using namespace std; struct tt //结构体保存点的下标和两点的长度的平方(整形没误差); { int len; int x,y; } p[200*200]; bool cmp(const tt &a,const tt &b) { return a.len < b.len; } int m[222][3]; // 原始数据数组; int le(int i,int j) // 求两点的长度; { return (m[i][0] - m[j][0])*(m[i][0] - m[j][0]) + (m[i][1] - m[j][1])*(m[i][1] - m[j][1])+ (m[i][2] - m[j][2])*(m[i][2] - m[j][2]); } struct point // 判断四点是否共面,后期用的模板,所以加了相应的结构,可优化; { int x,y,z; } px[5]; bool isok(int a1,int a2,int a3,int a4) // 判断四点是否共面; { px[0].x = m[a1][0],px[0].y = m[a1][1],px[0].z = m[a1][2]; px[1].x = m[a2][0],px[1].y = m[a2][1],px[1].z = m[a2][2]; px[2].x = m[a3][0],px[2].y = m[a3][1],px[2].z = m[a3][2]; px[3].x = m[a4][0],px[3].y = m[a4][1],px[3].z = m[a4][2]; int t,i,ans; point s1,s2,s3; s1.x=px[1].x-px[0].x; s1.y=px[1].y-px[0].y; s1.z=px[1].z-px[0].z; s2.x=px[2].x-px[0].x; s2.y=px[2].y-px[0].y; s2.z=px[2].z-px[0].z; s3.x=px[3].x-px[0].x; s3.y=px[3].y-px[0].y; s3.z=px[3].z-px[0].z; ans=s1.x*s2.y*s3.z+s1.y*s2.z*s3.x+s1.z*s2.x*s3.y-s1.z*s2.y*s3.x-s1.x*s2.z*s3.y-s1.y*s2.x*s3.z; if(ans==0) return true; else return false; } struct has //为用set去重加的数据结构,小白,set数据结构不熟,不懂自己百度; { int index[4]; bool operator < (const has &x)const { if(index[0]==x.index[0]) { if(index[1]==x.index[1]) { if(index[2]==x.index[2]) { if(index[3]==x.index[3]) { return index[3]<x.index[3]; } else return index[3]<x.index[3]; } else return index[2]<x.index[2]; } else return index[1]<x.index[1]; } else return index[0]<x.index[0]; } }; set<has> vis; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t,cas = 1; cin>>t; while(t--) { vis.clear(); int n; cin>>n; for(int i=0; i<n; i++) { cin>>m[i][0]>>m[i][1]>>m[i][2]; } int q=0; for(int i=0; i<n; i++) { for(int j=i+1; j<n; j++) { p[q].len=le(i,j); p[q].x = i; p[q++].y = j; } } long long ans = 0; sort(p,p+q,cmp); //排序,这个很重要; for(int i =0; i<q; i++) { tt p1 = p[i]; for(int j = i+1; p1.len == p[j].len; j++) //其中的条件是因为不相等就没有枚举的必要; { tt p2 = p[j]; if(isok(p1.x,p1.y,p2.x,p2.y)) continue; //共面成形,不成体; if(p1.x !=p2.y && p2.x != p1.y) //去掉有重点的边,因为我是要枚举两条相等的对边,再判断; { int len1 = le(p1.x,p2.x); int len2 = le(p1.x,p2.y); if(len1 == le(p1.y,p2.y) && len1 == p1.len) //四条边相等,又分两种情况,下面的存排,目的去重; { has aa; aa.index[0] = p1.x; aa.index[1] = p1.y; aa.index[2] = p2.x; aa.index[3] = p2.y; sort(aa.index,aa.index+4); if(vis.count(aa) != 1) { vis.insert(aa); ans++; } } else if( len2== le(p1.y,p2.x) && len2 == p2.len) { has aa; aa.index[0] = p1.x; aa.index[1] = p1.y; aa.index[2] = p2.x; aa.index[3] = p2.y; sort(aa.index,aa.index+4); if(vis.count(aa) != 1) { vis.insert(aa); ans++; } } } } } printf("Case #%d: %I64d\n",cas++,ans); } return 0; }
总结:枚举四个点,不现实,可以转化为边再枚举,并加优化;
标签:
原文地址:http://www.cnblogs.com/aishuijdemiaomiao/p/5770791.html