uvalive 4795 Paperweight

题意:给出一个5个顶点的多面体以及多面体内一点P。求让 多面体不同的方式(即以不同的面)放在地面上,设这个着地的面为A,多面体重心在A上的投影为B,在保证B在A内部且距离A的各个边界不小于0.2的前提 下(否则这种放置方式就是不合法的),求P距离地面的最大最小距离为多少。

思路:

(1)判断两个点是不是在面的同一侧;否则这个面就不能作为着地的面;

(2)计算重心;

(3)计算点在面的投影;

(4)计算点是否在面内;

(5)计算点到线的距离;

(6)计算点到面的距离。

特殊情况:四点共面当底面.

  1 #include<cstdio>
  2 #include<cmath>
  3 using namespace std;
  4
  5 const double eps = 1e-8;
  6 int dcmp(double x)
  7 {
  8     if(fabs(x) < eps) return 0;
  9     else return x < 0 ? -1 : 1;
 10 }
 11
 12 struct Point3
 13 {
 14     double x, y, z;
 15     Point3(double x=0, double y=0, double z=0):x(x),y(y),z(z) { }
 16 };
 17
 18 typedef Point3 Vector3;
 19
 20 Vector3 operator + (const Vector3& A, const Vector3& B)
 21 {
 22     return Vector3(A.x+B.x, A.y+B.y, A.z+B.z);
 23 }
 24
 25 Vector3 operator - (const Point3& A, const Point3& B)
 26 {
 27     return Vector3(A.x-B.x, A.y-B.y, A.z-B.z);
 28 }
 29
 30 Vector3 operator * (const Vector3& A, double p)
 31 {
 32     return Vector3(A.x*p, A.y*p, A.z*p);
 33 }
 34
 35 Vector3 operator / (const Vector3& A, double p)
 36 {
 37     return Vector3(A.x/p, A.y/p, A.z/p);
 38 }
 39
 40 double Dot(const Vector3& A, const Vector3& B)
 41 {
 42     return A.x*B.x + A.y*B.y + A.z*B.z;
 43 }
 44 double Length(const Vector3& A)
 45 {
 46     return sqrt(Dot(A, A));
 47 }
 48 double Angle(const Vector3& A, const Vector3& B)
 49 {
 50     return acos(Dot(A, B) / Length(A) / Length(B));
 51 }
 52 Vector3 Cross(const Vector3& A, const Vector3& B)
 53 {
 54     return Vector3(A.y*B.z - A.z*B.y, A.z*B.x - A.x*B.z, A.x*B.y - A.y*B.x);
 55 }
 56 double Area2(const Point3& A, const Point3& B, const Point3& C)
 57 {
 58     return Length(Cross(B-A, C-A));
 59 }
 60 double Volume6(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
 61 {
 62     return Dot(D-A, Cross(B-A, C-A));
 63 }
 64
 65 bool read_point3(Point3& p)
 66 {
 67     if(scanf("%lf%lf%lf", &p.x, &p.y, &p.z) != 3) return false;
 68     return true;
 69 }
 70
 71 // 点p到平面p0-n的距离。n必须为单位向量
 72 double DistanceToPlane(const Point3& p, const Point3& p0, const Vector3& n)
 73 {
 74     return fabs(Dot(p-p0, n)); // 如果不取绝对值,得到的是有向距离
 75 }
 76
 77 // 点p在平面p0-n上的投影。n必须为单位向量
 78 Point3 GetPlaneProjection(const Point3& p, const Point3& p0, const Vector3& n)
 79 {
 80     return p-n*Dot(p-p0, n);
 81 }
 82
 83 // 点P到直线AB的距离
 84 double DistanceToLine(const Point3& P, const Point3& A, const Point3& B)
 85 {
 86     Vector3 v1 = B - A, v2 = P - A;
 87     return Length(Cross(v1, v2)) / Length(v1);
 88 }
 89
 90 // p1和p2是否在线段a-b的同侧
 91 bool SameSide(const Point3& p1, const Point3& p2, const Point3& a, const Point3& b)
 92 {
 93     return dcmp(Dot(Cross(b-a, p1-a), Cross(b-a, p2-a))) >= 0;
 94 }
 95
 96 // 点在三角形P0, P1, P2中
 97 bool PointInTri(const Point3& P, const Point3& P0, const Point3& P1, const Point3& P2)
 98 {
 99     return SameSide(P, P0, P1, P2) && SameSide(P, P1, P0, P2) && SameSide(P, P2, P0, P1);
100 }
101
102 // 四面体的重心
103 Point3 Centroid(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
104 {
105     return (A + B + C + D)/4.0;
106 }
107
108 #include<algorithm>
109 //using namespace std;
110
111 // 判断P是否在三角形A, B, C中,并且到三条边的距离都至少为mindist。保证P, A, B, C共面
112 bool InsideWithMinDistance(const Point3& P, const Point3& A, const Point3& B, const Point3& C, double mindist)
113 {
114     if(!PointInTri(P, A, B, C)) return false;
115     if(DistanceToLine(P, A, B) < mindist) return false;
116     if(DistanceToLine(P, B, C) < mindist) return false;
117     if(DistanceToLine(P, C, A) < mindist) return false;
118     return true;
119 }
120
121 // 判断P是否在凸四边形ABCD(顺时针或逆时针)中,并且到四条边的距离都至少为mindist。保证P, A, B, C, D共面
122 bool InsideWithMinDistance(const Point3& P, const Point3& A, const Point3& B, const Point3& C, const Point3& D, double mindist)
123 {
124     if(!PointInTri(P, A, B, C)) return false;
125     if(!PointInTri(P, C, D, A)) return false;
126     if(DistanceToLine(P, A, B) < mindist) return false;
127     if(DistanceToLine(P, B, C) < mindist) return false;
128     if(DistanceToLine(P, C, D) < mindist) return false;
129     if(DistanceToLine(P, D, A) < mindist) return false;
130     return true;
131 }
132
133 int main()
134 {
135     for(int kase = 1; ; kase++)
136     {
137         Point3 P[5], F;
138         for(int i = 0; i < 5; i++)
139             if(!read_point3(P[i])) return 0;
140         read_point3(F);
141
142         // 求重心坐标
143         Point3 c1 = Centroid(P[0], P[1], P[2], P[3]);
144         Point3 c2 = Centroid(P[0], P[1], P[2], P[4]);
145         double vol1 = fabs(Volume6(P[0], P[1], P[2], P[3])) / 6.0;
146         double vol2 = fabs(Volume6(P[0], P[1], P[2], P[4])) / 6.0;
147         Point3 centroid = (c1 * vol1 + c2 * vol2) / (vol1 + vol2);
148
149         // 枚举放置方案
150         double mindist = 1e9, maxdist = -1e9;
151         for(int i = 0; i < 5; i++)
152             for(int j = i+1; j < 5; j++)
153                 for(int k = j+1; k < 5; k++)
154                 {
155                     // 找出另外两个点的下标a和b
156                     int vis[5] = {0};
157                     vis[i] = vis[j] = vis[k] = 1;
158                     int a, b;
159                     for(a = 0; a < 5; a++) if(!vis[a])
160                         {
161                             b = 10-i-j-k-a;
162                             break;
163                         }
164
165                     // 判断a和b是否在平面i-j-k的异侧(体积法判断)
166                     int d1 = dcmp(Volume6(P[i], P[j], P[k], P[a]));
167                     int d2 = dcmp(Volume6(P[i], P[j], P[k], P[b]));
168                     if(d1 * d2 < 0) continue; // 是,则放置方案不合法
169
170                     Vector3 n = Cross(P[j]-P[i], P[k]-P[i]); // 法向量
171                     n = n / Length(n); // 单位化
172
173                     Point3 proj = GetPlaneProjection(centroid, P[i], n); // 重心在平面i-j-k上的投影
174                     bool ok = InsideWithMinDistance(proj, P[i], P[j], P[k], 0.2);
175                     if(!ok)
176                     {
177                         if(d1 == 0)   // i-j-k-a四点共面。i和j一定为ABC三个顶点之一,k和a是D或者E
178                         {
179                             if(!InsideWithMinDistance(proj, P[i], P[k], P[j], P[a], 0.2)) continue;
180                         }
181                         else if(d2 == 0)     // i-j-k-b四点共面。i和j一定为ABC三个顶点之一,k和b是D或者E
182                         {
183                             if(!InsideWithMinDistance(proj, P[i], P[k], P[j], P[b], 0.2)) continue;
184                         }
185                         else
186                             continue;
187                     }
188
189                     // 更新答案
190                     double dist = DistanceToPlane(F, P[i], n);
191                     mindist = min(mindist, dist);
192                     maxdist = max(maxdist, dist);
193                 }
194         printf("Case %d: %.5lf %.5lf\n", kase, mindist, maxdist);
195     }
196     return 0;
197 }

时间: 2024-10-05 15:47:49

uvalive 4795 Paperweight的相关文章

UVALive 4848 Tour Belt

F - Tour Belt Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVALive 4848 Description Korea has many tourist attractions. One of them is an archipelago (Dadohae in Korean), a cluster of small islands sca

UVALive 6467 Strahler Order 拓扑排序

这题是今天下午BNU SUMMER TRAINING的C题 是队友给的解题思路,用拓扑排序然后就可以了 最后是3A 其中两次RE竟然是因为: scanf("%d",mm); ORZ 以后能用CIN还是CIN吧 QAQ 贴代码了: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostre

UVALive 7077 Little Zu Chongzhi&#39;s Triangles (有序序列和三角形的关系)

这个题……我上来就给读错了,我以为最后是一个三角形,一条边可以由多个小棒组成,所以想到了状态压缩各种各样的东西,最后成功了……结果发现样例过不了,三条黑线就在我的脑袋上挂着,改正了以后我发现N非常小,想到了回溯每个棍的分组,最多分5组,结果发现超时了……最大是5^12 =  244,140,625,厉害呢…… 后来想贪心,首先想暴力出所有可能的组合,结果发现替换问题是一个难题……最后T T ,我就断片了.. 等看了别人的办法以后,我才发现我忽视了三角形的特性,和把数据排序以后的特点. 如果数据从

Gym 100299C &amp;&amp; UVaLive 6582 Magical GCD (暴力+数论)

题意:给出一个长度在 100 000 以内的正整数序列,大小不超过 10^ 12.求一个连续子序列,使得在所有的连续子序列中, 它们的GCD值乘以它们的长度最大. 析:暴力枚举右端点,然后在枚举左端点时,我们对gcd相同的只保留一个,那就是左端点最小的那个,只有这样才能保证是最大,然后删掉没用的. UVaLive上的数据有问题,比赛时怎么也交不过,后来去别的oj交就过了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000&qu

UVALive 6511 Term Project

Term Project Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Original ID: 651164-bit integer IO format: %lld      Java class name: Main 解题:强连通分量 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1

UVALive 6508 Permutation Graphs

Permutation Graphs Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Original ID: 650864-bit integer IO format: %lld      Java class name: Main 解题:逆序数 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long l

UVALive 2659+HUST 1017+ZOJ 3209 (DLX

UVALive 2659 题目:16*16的数独.试了一发大白模板. /* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include

UVALive 5545 Glass Beads

Glass Beads Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Original ID: 554564-bit integer IO format: %lld      Java class name: Main Once upon a time there was a famous actress. As you may expect, she played mostly

UVALive 6145 Version Controlled IDE(可持久化treap、rope)

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4156 题目拷贝难度大我就不复制了. 题目大意:维护一个字符串,要求支持插入.删除操作,还有输出第 i 次操作后的某个子串.强制在线. 思路1:使用可持久化treap可破,详细可见CLJ的<可持久化数据结构的研究>. 思路2:rope大法好,详见:http