CCPC2016 网络赛 hdu5839 Special Tetrahedron

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

给定空间中n个不相同的点,求所有特殊四面体的个数。(n <= 200)

特殊四边形是满足以下条件的四面体:

1、至少有4条边相等。

2、如果只有四条边相等,则剩余两条边不相邻。

 

分析题意,可以知道我们要求的是这样的四面体:

图中四条红边必须相等,但黑边不一定相等。蓝色平面是i,j两点所连线段的垂直平分面,由此可知两条蓝边也必须相等。

由此可以很自然地得到做法:枚举i和j,对所有在ij中垂面上的点k,计算其到ij的距离,排序后相同距离的归为一组。若一组有m个,则有m*(m-1)/2种方法可以生成目标四面体。

为了避免计算重复并减小常数,限制 i < j,k,即对于某个四面体,取其四个顶点中编号最小的那个点 i,用 i 所在的黑边去给它计数。时间复杂度O(n^3*logn)

不过,麻烦的问题是正四面体和四点共面的存在。

假设不是正四面体的所求四面体数为x,正四面体数为y,满足上述统计方法中性质的四点共面有z种。那么直接按上述方法统计所得结果为 x+3y+z。注意正四面体会被与i相连的三条边统计三次。

如何去掉正四面体和四点共面的影响呢?只要统计一下他们两类的个数就行了。具体方法和多校 How many triangles 类似,对于同一类的,按照角度排序(图中theta),再扫一遍就行了。不过这是三维的,角度的处理比较复杂。我的具体方法是以k循环中第一个点k1为起始点(角度为0),用点积算出虚拟二维坐标系中的x,用叉积算出y(因为三维叉积是一个向量,要取其模为y的模,根据向量和ij向量是否同向确定其正负),一个atan2就ok了。

其它技巧,因为题目中所有数字均为正数而且 -2000<=x<=2000,所以除了极角排序用double外,其余全用int就行了。输入的所有点坐标都可以乘以二,这样线段 ij 的中点坐标也可以用整数表示了。

具体代码因为复制粘贴,比较长:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <string>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <cmath>
  7 using namespace std;
  8 
  9 const int N = 205;
 10 const double pi = acos(-1.0);
 11 
 12 struct point {
 13     int x,y,z;
 14     point() {}
 15     point(int xx,int yy,int zz) {
 16         x = xx,y = yy,z = zz;
 17     }
 18     void input() {
 19         cin >> x >> y >> z;
 20         x *= 2, y *= 2, z *= 2;
 21     }
 22     point operator -(const point &n2) const {
 23         return point(x-n2.x, y-n2.y, z-n2.z);
 24     }
 25     point operator +(const point &n2) const {
 26         return point(x+n2.x, y+n2.y, z+n2.z);
 27     }
 28     point operator /(const int n) const {
 29         return point(x/n, y/n, z/n);
 30     }
 31     bool operator ==(const point &n2) const {
 32         return x==n2.x && y==n2.y && z==n2.z;
 33     }
 34 }a[N];
 35 
 36 struct sta {
 37     int x, id;
 38     sta() {}
 39     sta(int xx, int idd) {
 40         x = xx; id = idd;
 41     }
 42     bool operator <(const sta &n2) const {
 43         return x<n2.x;
 44     }
 45 }b[N*2];
 46 
 47 struct angle {
 48     double x; int id;
 49     angle() {}
 50     angle(double xx, int idd) {
 51         x = xx; id = idd;
 52     }
 53     bool operator <(const angle &n2) const {
 54         return x<n2.x;
 55     }
 56     void output() {
 57         cout << "angle " << x <<' ' << id << endl;
 58     }
 59 }c[N*2];
 60 
 61 point det(const point &p1, const point &p2)
 62 {
 63     return point(p1.y*p2.z-p2.y*p1.z, -p1.x*p2.z+p2.x*p1.z, p1.x*p2.y-p2.x*p1.y);
 64 }
 65 int len_sqr(const point &p)
 66 {
 67     return p.x*p.x + p.y*p.y + p.z*p.z;
 68 }
 69 int dot(const point &p1, const point &p2)
 70 {
 71     return p1.x*p2.x + p1.y*p2.y + p1.z*p2.z;
 72 }
 73 int sig(int x)
 74 {
 75     return x==0? 0: (x>0? 1:-1);
 76 }
 77 
 78 int main()
 79 {    
 80     int test,n,i,j,k;
 81     cin >> test;
 82     for(int t = 1; t<=test; t++)
 83     {
 84         cin >> n;
 85         for(i = 1; i<=n; i++) a[i].input();
 86         long long ans = 0;// x+3y+z
 87         long long ans2 = 0;// 3y
 88         long long ans3 = 0;//z
 89         for(i = 1; i<=n; i++)
 90             for(j = i+1; j<=n; j++)
 91             {
 92                 point mid = (a[i]+a[j])/2, z = a[i]-a[j];
 93                 int l2 = len_sqr(z);
 94                 int tot = 0;
 95                 for(k = i+1; k<=n; k++) 
 96                 {
 97                     if(dot(a[k]-mid, z)==0)
 98                         b[++tot] = sta(len_sqr(mid-a[k]), k);
 99                 }
100                 sort(b+1, b+1+tot);
101 
102                 int now;
103                 for(k = 1; k<=tot; k++)
104                 {
105                     now = 1;
106                     while(k<tot && b[k].x==b[k+1].x) {
107                         now++; k++;
108                     }
109                     if(now>1)
110                         ans += now*(now-1)/2; 
111                 }
112                 
113                 for(k = 1; k<=tot; k++)
114                 {
115 
116                     int from = k;
117                     while(k<tot && b[k].x==b[k+1].x) {
118                         k++;
119                     }
120                     int to = k;        
121                     if(b[k].x*4==l2*3) {
122                         
123                         int m = 0;
124                         for(k = from; k<=to; k++)
125                         {
126                             point temp = det(a[b[from].id]-mid, a[b[k].id]-mid);
127                             int x = dot(a[b[from].id]-mid, a[b[k].id]-mid);
128                             if(temp==point(0,0,0))
129                             {
130                                 if(x>0)
131                                     c[++m] = angle(.0, b[k].id);
132                                 else
133                                     c[++m] = angle(pi, b[k].id);
134                             }
135                             else {
136                                 double y = sqrt(len_sqr(temp)),theta;
137                                 if(sig(temp.x)==sig(z.x) && sig(temp.y)==sig(z.y) && sig(temp.z)==sig(z.z))
138                                     theta = atan2(y, x);
139                                 else
140                                     theta = atan2(-y, x);
141                                 if(theta<0) theta += 2.0*pi;
142                                 c[++m] = angle(theta, b[k].id);
143                             }
144                         }
145                         sort(c+1, c+1+m);
146                         for(k = m+1; k<=m*2; k++)
147                         {
148                             c[k] = c[k-m];
149                             c[k].x += 2*pi;
150                         }
151                         int p = 1;
152                         for(k = 1; k<=m; k++)
153                         {
154                             while(c[p+1].x-c[k].x<pi && dot(a[c[p+1].id]-mid, a[c[k].id]-mid)*4>=l2)
155                                 p++;
156                             if(dot(a[c[p].id]-mid, a[c[k].id]-mid)*4==l2) ans2++;
157                         }
158                     }
159                     //
160                     int m = 0;
161                     for(k = from; k<=to; k++)
162                     {
163                         point temp = det(a[b[from].id]-mid, a[b[k].id]-mid);
164                         int x = dot(a[b[from].id]-mid, a[b[k].id]-mid);
165                         if(temp==point(0,0,0))
166                         {
167                             if(x>0)
168                                 c[++m] = angle(.0, b[k].id);
169                             else
170                                 c[++m] = angle(pi, b[k].id);
171                         }
172                         else {
173                             double y = sqrt(len_sqr(temp)),theta;
174                             if(sig(temp.x)==sig(z.x) && sig(temp.y)==sig(z.y) && sig(temp.z)==sig(z.z))
175                                 theta = atan2(y, x);
176                             else
177                                 theta = atan2(-y, x);
178                             if(theta<0) theta += 2.0*pi;
179                             c[++m] = angle(theta, b[k].id);
180                         }
181                     }
182                     sort(c+1, c+1+m);
183                     for(k = m+1; k<=m*2; k++)
184                     {
185                         c[k] = c[k-m];
186                         c[k].x += 2*pi;
187                     }
188                     int p = 1;
189                     for(k = 1; k<=m; k++)
190                     {
191                         while(1) {
192                             if(p==2*m) break;
193                             point temp = det(a[c[k].id]-mid, a[c[p+1].id]-mid);
194                             if(c[p+1].x-c[k].x<4 &&( sig(temp.x)==sig(z.x) && sig(temp.y)==sig(z.y) && sig(temp.z)==sig(z.z) || temp==point(0,0,0)))
195                                 p++;
196                             else break;
197                         }
198         
199                         if(c[p].x-c[k].x > 1 && det(a[c[p].id]-mid, a[c[k].id]-mid)==point(0,0,0)) ans3++;
200                     }
201                     k = to;
202                 }
203 
204             }
205 
206 
207         ans = ans-ans2-ans3/2+ans2/3;
208         
209         printf("Case #%d: %I64d\n", t, ans);
210     }
211     return 0;
212 }
View Code

 

转载于:https://www.cnblogs.com/liuaohan/p/5772228.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值