zoukankan      html  css  js  c++  java
  • 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
    ", kase, mindist, maxdist);
    195     }
    196     return 0;
    197 }
    View Code
  • 相关阅读:
    程序员的7中武器
    需要强化的知识
    微软中国联合小i推出MSN群Beta 不需任何插件
    XML Notepad 2006 v2.0
    Sandcastle August 2006 Community Technology Preview
    [推荐] TechNet 广播 SQL Server 2000完结篇
    《太空帝国 4》(Space Empires IV)以及 xxMod 英文版 中文版 TDM Mod 英文版 中文版
    IronPython 1.0 RC2 更新 1.0.60816
    Microsoft .NET Framework 3.0 RC1
    《Oracle Developer Suite 10g》(Oracle Developer Suite 10g)V10.1.2.0.2
  • 原文地址:https://www.cnblogs.com/ITUPC/p/4906974.html
Copyright © 2011-2022 走看看