题意:给出一个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. Extjs4 treePanel异步加载菜单(后台从数据库读取)

    运行环境:springMVC+mybatis 一.建表 说明:0表示此节点为非叶子节点,即此节点还包括了子节点:1表示此节点为叶子节点,即此节点没有子节点.:关于图标iconCls是从Extjs的文件 ...

  2. @Entity设置实体lazy = false

    问题描述 在通过Hibernate查询Bean信息时报以下异常信息: org.hibernate.LazyInitializationException: could not initialize p ...

  3. html5 Doctor——教你规范使用html5标签

    学习地址(英文资料):http://html5doctor.com/ http://www.w3.org/html/wg/drafts/html/master/text-level-semantics ...

  4. uva 10608

    简单并查集  水水..... #include <cstdio> #include <cstring> #define maxn 30005 int fa[maxn],ans[ ...

  5. jquery类选择器无法取得对象问题原因

    <html> <script type="text/javascript" src="jquery-1.9.1.js"></scr ...

  6. php继承与重载

    <?php class A { public $param = "paramA"; public function test() { echo "testA&quo ...

  7. HDMI介绍与流程

    HDMI接口 http://baike.c114.net/view.asp?id=17671-21565442 DDC(Display Data Channel)通道用于HDMI发送和接收端之间交换一 ...

  8. redis的key过期时间

    public void set(String key,String value,int liveTime){ this.set(key, value); this.getJedis().expire( ...

  9. winform学习日志(十九)----------真正三层架构之登录

    摘要:一:三层构架的基础知识在项目开发的过程中,有时把整个项目分为三层架构,其中包括:表示层(UI).业务逻辑层(BLL)和数据访问层(DAL).三层的作用分别如下: 表示层:为用户提供交互操作界面, ...

  10. Qt: 自动调整到最合适的大小(不是很明白)

    SortDialog::SortDialog(QWidget *parent) : QDialog(parent) { setupUi(this); groupBox_2->hide(); gr ...