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

思路:

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

(2)计算重心;

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

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

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

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

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

 #include<cstdio>
#include<cmath>
using namespace std; const double eps = 1e-;
int dcmp(double x)
{
if(fabs(x) < eps) return ;
else return x < ? - : ;
} struct Point3
{
double x, y, z;
Point3(double x=, double y=, double z=):x(x),y(y),z(z) { }
}; typedef Point3 Vector3; Vector3 operator + (const Vector3& A, const Vector3& B)
{
return Vector3(A.x+B.x, A.y+B.y, A.z+B.z);
} Vector3 operator - (const Point3& A, const Point3& B)
{
return Vector3(A.x-B.x, A.y-B.y, A.z-B.z);
} Vector3 operator * (const Vector3& A, double p)
{
return Vector3(A.x*p, A.y*p, A.z*p);
} Vector3 operator / (const Vector3& A, double p)
{
return Vector3(A.x/p, A.y/p, A.z/p);
} double Dot(const Vector3& A, const Vector3& B)
{
return A.x*B.x + A.y*B.y + A.z*B.z;
}
double Length(const Vector3& A)
{
return sqrt(Dot(A, A));
}
double Angle(const Vector3& A, const Vector3& B)
{
return acos(Dot(A, B) / Length(A) / Length(B));
}
Vector3 Cross(const Vector3& A, const Vector3& B)
{
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);
}
double Area2(const Point3& A, const Point3& B, const Point3& C)
{
return Length(Cross(B-A, C-A));
}
double Volume6(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
{
return Dot(D-A, Cross(B-A, C-A));
} bool read_point3(Point3& p)
{
if(scanf("%lf%lf%lf", &p.x, &p.y, &p.z) != ) return false;
return true;
} // 点p到平面p0-n的距离。n必须为单位向量
double DistanceToPlane(const Point3& p, const Point3& p0, const Vector3& n)
{
return fabs(Dot(p-p0, n)); // 如果不取绝对值,得到的是有向距离
} // 点p在平面p0-n上的投影。n必须为单位向量
Point3 GetPlaneProjection(const Point3& p, const Point3& p0, const Vector3& n)
{
return p-n*Dot(p-p0, n);
} // 点P到直线AB的距离
double DistanceToLine(const Point3& P, const Point3& A, const Point3& B)
{
Vector3 v1 = B - A, v2 = P - A;
return Length(Cross(v1, v2)) / Length(v1);
} // p1和p2是否在线段a-b的同侧
bool SameSide(const Point3& p1, const Point3& p2, const Point3& a, const Point3& b)
{
return dcmp(Dot(Cross(b-a, p1-a), Cross(b-a, p2-a))) >= ;
} // 点在三角形P0, P1, P2中
bool PointInTri(const Point3& P, const Point3& P0, const Point3& P1, const Point3& P2)
{
return SameSide(P, P0, P1, P2) && SameSide(P, P1, P0, P2) && SameSide(P, P2, P0, P1);
} // 四面体的重心
Point3 Centroid(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
{
return (A + B + C + D)/4.0;
} #include<algorithm>
//using namespace std; // 判断P是否在三角形A, B, C中,并且到三条边的距离都至少为mindist。保证P, A, B, C共面
bool InsideWithMinDistance(const Point3& P, const Point3& A, const Point3& B, const Point3& C, double mindist)
{
if(!PointInTri(P, A, B, C)) return false;
if(DistanceToLine(P, A, B) < mindist) return false;
if(DistanceToLine(P, B, C) < mindist) return false;
if(DistanceToLine(P, C, A) < mindist) return false;
return true;
} // 判断P是否在凸四边形ABCD(顺时针或逆时针)中,并且到四条边的距离都至少为mindist。保证P, A, B, C, D共面
bool InsideWithMinDistance(const Point3& P, const Point3& A, const Point3& B, const Point3& C, const Point3& D, double mindist)
{
if(!PointInTri(P, A, B, C)) return false;
if(!PointInTri(P, C, D, A)) return false;
if(DistanceToLine(P, A, B) < mindist) return false;
if(DistanceToLine(P, B, C) < mindist) return false;
if(DistanceToLine(P, C, D) < mindist) return false;
if(DistanceToLine(P, D, A) < mindist) return false;
return true;
} int main()
{
for(int kase = ; ; kase++)
{
Point3 P[], F;
for(int i = ; i < ; i++)
if(!read_point3(P[i])) return ;
read_point3(F); // 求重心坐标
Point3 c1 = Centroid(P[], P[], P[], P[]);
Point3 c2 = Centroid(P[], P[], P[], P[]);
double vol1 = fabs(Volume6(P[], P[], P[], P[])) / 6.0;
double vol2 = fabs(Volume6(P[], P[], P[], P[])) / 6.0;
Point3 centroid = (c1 * vol1 + c2 * vol2) / (vol1 + vol2); // 枚举放置方案
double mindist = 1e9, maxdist = -1e9;
for(int i = ; i < ; i++)
for(int j = i+; j < ; j++)
for(int k = j+; k < ; k++)
{
// 找出另外两个点的下标a和b
int vis[] = {};
vis[i] = vis[j] = vis[k] = ;
int a, b;
for(a = ; a < ; a++) if(!vis[a])
{
b = -i-j-k-a;
break;
} // 判断a和b是否在平面i-j-k的异侧(体积法判断)
int d1 = dcmp(Volume6(P[i], P[j], P[k], P[a]));
int d2 = dcmp(Volume6(P[i], P[j], P[k], P[b]));
if(d1 * d2 < ) continue; // 是,则放置方案不合法 Vector3 n = Cross(P[j]-P[i], P[k]-P[i]); // 法向量
n = n / Length(n); // 单位化 Point3 proj = GetPlaneProjection(centroid, P[i], n); // 重心在平面i-j-k上的投影
bool ok = InsideWithMinDistance(proj, P[i], P[j], P[k], 0.2);
if(!ok)
{
if(d1 == ) // i-j-k-a四点共面。i和j一定为ABC三个顶点之一,k和a是D或者E
{
if(!InsideWithMinDistance(proj, P[i], P[k], P[j], P[a], 0.2)) continue;
}
else if(d2 == ) // i-j-k-b四点共面。i和j一定为ABC三个顶点之一,k和b是D或者E
{
if(!InsideWithMinDistance(proj, P[i], P[k], P[j], P[b], 0.2)) continue;
}
else
continue;
} // 更新答案
double dist = DistanceToPlane(F, P[i], n);
mindist = min(mindist, dist);
maxdist = max(maxdist, dist);
}
printf("Case %d: %.5lf %.5lf\n", kase, mindist, maxdist);
}
return ;
}

uvalive 4795 Paperweight的更多相关文章

  1. UVALive - 4108 SKYLINE[线段树]

    UVALive - 4108 SKYLINE Time Limit: 3000MS     64bit IO Format: %lld & %llu Submit Status uDebug ...

  2. UVALive - 3942 Remember the Word[树状数组]

    UVALive - 3942 Remember the Word A potentiometer, or potmeter for short, is an electronic device wit ...

  3. UVALive - 3942 Remember the Word[Trie DP]

    UVALive - 3942 Remember the Word Neal is very curious about combinatorial problems, and now here com ...

  4. 思维 UVALive 3708 Graveyard

    题目传送门 /* 题意:本来有n个雕塑,等间距的分布在圆周上,现在多了m个雕塑,问一共要移动多少距离: 思维题:认为一个雕塑不动,视为坐标0,其他点向最近的点移动,四舍五入判断,比例最后乘会10000 ...

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

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...

  6. UVALive 6508 Permutation Graphs

    Permutation Graphs Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit ...

  7. UVALive 6500 Boxes

    Boxes Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Pract ...

  8. UVALive 6948 Jokewithpermutation dfs

    题目链接:UVALive 6948  Jokewithpermutation 题意:给一串数字序列,没有空格,拆成从1到N的连续数列. dfs. 可以计算出N的值,也可以直接检验当前数组是否合法. # ...

  9. 【暑假】[实用数据结构]UVAlive 3135 Argus

    UVAlive 3135 Argus Argus Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %l ...

随机推荐

  1. c++ 读写锁

    #ifndef THREAD_UTIL_H #define THREAD_UTIL_H #include <pthread.h> namespace spider { class Auto ...

  2. 用户自定义结构数据与VARIANT转换 .

    用户自定义结构数据与VARIANT转换 cheungmine 将用户自定义的C结构数据存储成VARIANT类型,需要时再将VARIANT类型转为用户自定义的结构数据,有十分现实的意义,既然我们不想为这 ...

  3. ASP.NET 4.5.256 has not been registered on the Web server

    请见:http://answers.microsoft.com/en-us/insider/forum/insider_apps-insider_other/aspnet-45256-has-not- ...

  4. Eclipse不能自动编译 java文件的解决方案

    前段时间出现了eclipse 不自动编译java文件的问题,在网上找了好长时间,总算把问题解决了,现在把这个问题的解决方法总结一下. 1,看看project -- Build Automaticall ...

  5. Spring中的Resource

    Spring中的资源定义:Resource此接口的全名为:org.springframework.core.io.Resource比较常用的资源定义的实现类为:1.ClassPathResource ...

  6. cache设计,以及多核造成的不一致性以及解决方案

    http://www.360doc.com/content/11/1013/00/1317564_155625188.shtml http://blog.csdn.net/muxiqingyang/a ...

  7. Node.js学习(11)----HTTP服务器与客户端

    Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基于事件的 HTTP 服务器,它的核心由 Node.js ...

  8. XMPP聊天客户端环境搭建

    1.服务器选择:ejabberd,具体安装过程请参考:http://blog.csdn.net/linhanmin/article/details/9876819 2.客户端配置: 采用xmppfra ...

  9. wince下sources\sources.cmn\Makefile.def的相关作用

    1:首先是Makefile.def: ---------------------------------------- 在所有驱动的makefile中有!INCLUDE $(_MAKEENVROOT) ...

  10. sed找到重复的行

    sed之仅打印相邻重复的行 cat file  aaa bbb bbb ccc ddd eee eee fff   只显示重复的行: bbb bbb eee eee   sed -n ':a;N;/\ ...