题意:给出一个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. CQRS学习——最小单元的Cqrs(CommandEvent)[其一]

    [说明:博主采用边写边思考的方式完成这一系列的博客,所以代码以附件为准,文中代码仅为了说明.] 结构 在学习和实现CQRS的过程中,首要参考的项目是这个[http://www.cnblogs.com/ ...

  2. CSRF防范策略研究

    目录 0x1:检查网页的来源 0x2:检查内置的隐藏变量 0x3:用POST不用GET 检查网页的来源应该怎么做呢?首先我们应该检查$_SERVER[“HTTP_REFERER”]的值与来源网页的网址 ...

  3. MonoBehaviour的事件和具体功能总结

    原地址:http://blog.csdn.net/dingxiaowei2013/article/details/26215577 苦于Visual Studio 2013没有对MonoBehavio ...

  4. 如何在eclipse里使用git

    新版都自带git插件了.在项目上右键,选team,选share project,再选择git就可以了. 如果在本地使用git比较简单.如果要多人共享的使用git,那么需要专门的服务器,并提供ssh,这 ...

  5. 使用intellij idea搭建MAVEN+springmvc+mybatis框架

    原文:使用intellij idea搭建MAVEN+springmvc+mybatis框架 1.首先使用idea创建一个maven项目 2.接着配置pom.xml,以下为我的配置 <projec ...

  6. web.xml的说明

    <!--DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. Copyright 2000-2007 Sun Microsystems ...

  7. NFC(12)使用Android Beam技术传输文本数据及它是什么

    Android Beam技术是什么 Android Beam的基本理念就是两部(只能是1对1,不可像蓝牙那样1对多)NFC设备靠近时(一般是背靠背),通过触摸一部NFC设备的屏幕,将数据推向另外一部N ...

  8. Zookeeper基本知识

    Zookeeper的Session: (1)客户端和server间采用长连接 (2)连接建立后,server产生session ID(64位)返还给客户端 (3)客户端定期发送ping包来检查和保持和 ...

  9. java之内部类与匿名内部类

    Java 内部类 分四种:成员内部类.局部内部类.静态内部类和匿名内部类. 1.成员内部类: 即作为外部类的一个成员存在,与外部类的属性.方法并列. 注意:成员内部类中不能定义静态变量,但可以访问外部 ...

  10. SGU185 - Two Shortest

    原题地址:http://acm.sgu.ru/problem.php?contest=0&problem=185 题目大意:给出一个无向图,求出从 1 到 n 的两条没有相同边的最短路径(允许 ...